GCC Code Coverage Report


Directory: ./
File: client/mysqltest.cc
Date: 2022-12-13 11:44:05
Exec Total Coverage
Lines: 4050 4807 84.3%
Branches: 3774 6797 55.5%

Line Branch Exec Source
1 // Copyright (c) 2000, 2022, Oracle and/or its affiliates.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License, version 2.0,
5 // as published by the Free Software Foundation.
6 //
7 // This program is also distributed with certain software (including
8 // but not limited to OpenSSL) that is licensed under separate terms,
9 // as designated in a particular file or component or in included license
10 // documentation. The authors of MySQL hereby grant you an additional
11 // permission to link the program and your derivative works with the
12 // separately licensed software that they have included with MySQL.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License, version 2.0, for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 /// @file
24 ///
25 /// mysqltest client - Tool used for executing a .test file.
26 ///
27 /// See @ref PAGE_MYSQL_TEST_RUN "The MySQL Test Framework" for more
28 /// information.
29
30 #include "client/client_query_attributes.h"
31 #include "client/mysqltest/error_names.h"
32 #include "client/mysqltest/expected_errors.h"
33 #include "client/mysqltest/expected_warnings.h"
34 #include "client/mysqltest/logfile.h"
35 #include "client/mysqltest/regular_expressions.h"
36 #include "client/mysqltest/secondary_engine.h"
37 #include "client/mysqltest/utils.h"
38 #include "compression.h"
39
40 #include <algorithm>
41 #include <chrono>
42 #include <cmath> // std::isinf
43 #include <limits>
44 #include <new>
45 #include <sstream>
46 #ifdef _WIN32
47 #include <thread> // std::thread
48 #endif
49
50 #include <assert.h>
51 #if defined MY_MSCRT_DEBUG || defined _WIN32
52 #include <crtdbg.h>
53 #endif
54 #ifdef _WIN32
55 #include <direct.h>
56 #endif
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <limits.h>
60 #include <mysql_async.h>
61 #include <mysql_version.h>
62 #include <mysqld_error.h>
63 #include <signal.h>
64 #include <stdarg.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <sys/types.h>
68 #ifndef _WIN32
69 #include <poll.h>
70 #include <sys/time.h>
71 #include <sys/wait.h>
72 #endif
73 #ifdef _WIN32
74 #include <windows.h>
75 #endif
76
77 #include "caching_sha2_passwordopt-vars.h"
78 #include "client/client_priv.h"
79 #include "m_ctype.h"
80 #include "map_helpers.h"
81 #include "mf_wcomp.h" // wild_compare
82 #include "my_compiler.h"
83 #include "my_config.h"
84 #include "my_dbug.h"
85 #include "my_default.h"
86 #include "my_dir.h"
87 #include "my_inttypes.h"
88 #include "my_macros.h"
89 #include "my_openssl_fips.h"
90 #include "my_pointer_arithmetic.h"
91 #include "my_stacktrace.h"
92 #include "my_systime.h" // my_sleep()
93 #include "my_thread_local.h"
94 #include "prealloced_array.h"
95 #include "print_version.h"
96 #include "sql_common.h"
97 #include "template_utils.h"
98 #include "typelib.h"
99 #include "violite.h"
100 #include "welcome_copyright_notice.h" // ORACLE_WELCOME_COPYRIGHT_NOTICE
101
102 #ifdef _WIN32
103 #define SIGNAL_FMT "exception 0x%x"
104 #else
105 #define SIGNAL_FMT "signal %d"
106 #endif
107
108 #ifdef _WIN32
109 #define setenv(a, b, c) _putenv_s(a, b)
110 #define popen _popen
111 #define pclose _pclose
112 #endif
113
114 #define MAX_VAR_NAME_LENGTH 256
115 #define MAX_COLUMNS 256
116 #define MAX_DELIMITER_LENGTH 16
117 #define DEFAULT_MAX_CONN 1024
118 #define REPLACE_ROUND_MAX 16
119
120 /* Flags controlling send and reap */
121 #define QUERY_SEND_FLAG 1
122 #define QUERY_REAP_FLAG 2
123
124 #define APPEND_TYPE(type) \
125 { \
126 dynstr_append(ds, "-- "); \
127 switch (type) { \
128 case SESSION_TRACK_SYSTEM_VARIABLES: \
129 dynstr_append(ds, "Tracker : SESSION_TRACK_SYSTEM_VARIABLES\n"); \
130 break; \
131 case SESSION_TRACK_SCHEMA: \
132 dynstr_append(ds, "Tracker : SESSION_TRACK_SCHEMA\n"); \
133 break; \
134 case SESSION_TRACK_STATE_CHANGE: \
135 dynstr_append(ds, "Tracker : SESSION_TRACK_STATE_CHANGE\n"); \
136 break; \
137 case SESSION_TRACK_GTIDS: \
138 dynstr_append(ds, "Tracker : SESSION_TRACK_GTIDS\n"); \
139 break; \
140 case SESSION_TRACK_TRANSACTION_CHARACTERISTICS: \
141 dynstr_append( \
142 ds, "Tracker : SESSION_TRACK_TRANSACTION_CHARACTERISTICS\n"); \
143 break; \
144 case SESSION_TRACK_TRANSACTION_STATE: \
145 dynstr_append(ds, "Tracker : SESSION_TRACK_TRANSACTION_STATE\n"); \
146 break; \
147 default: \
148 dynstr_append(ds, "\n"); \
149 } \
150 }
151
152 extern CHARSET_INFO my_charset_utf16le_bin;
153
154 // List of error codes specified with 'error' command.
155 Expected_errors *expected_errors = new Expected_errors();
156
157 // List of warnings disabled with 'disable_warnings' command.
158 Expected_warnings *disabled_warnings = new Expected_warnings();
159
160 // List of warnings enabled with 'enable_warnings' command.
161 Expected_warnings *enabled_warnings = new Expected_warnings();
162
163 enum {
164 OPT_COLORED_DIFF = OPT_MAX_CLIENT_OPTION,
165 OPT_CURSOR_PROTOCOL,
166 OPT_EXPLAIN_PROTOCOL,
167 OPT_HYPERGRAPH,
168 OPT_JSON_EXPLAIN_PROTOCOL,
169 OPT_LOG_DIR,
170 OPT_MARK_PROGRESS,
171 OPT_MAX_CONNECT_RETRIES,
172 OPT_MAX_CONNECTIONS,
173 OPT_NO_SKIP,
174 OPT_OFFLOAD_COUNT_FILE,
175 OPT_PS_PROTOCOL,
176 OPT_RESULT_FORMAT_VERSION,
177 #ifdef _WIN32
178 OPT_SAFEPROCESS_PID,
179 #endif
180 OPT_SP_PROTOCOL,
181 OPT_TAIL_LINES,
182 OPT_TRACE_EXEC,
183 OPT_TRACE_PROTOCOL,
184 OPT_VIEW_PROTOCOL,
185 };
186
187 static int record = 0;
188 static char *opt_db = nullptr, *opt_pass = nullptr;
189 const char *opt_user = nullptr, *opt_host = nullptr, *unix_sock = nullptr,
190 *opt_basedir = "./";
191 const char *excluded_string = nullptr;
192 static char *shared_memory_base_name = nullptr;
193 const char *opt_logdir = "";
194 const char *opt_include = nullptr, *opt_charsets_dir;
195 static int opt_port = 0;
196 static int opt_max_connect_retries;
197 static int opt_result_format_version;
198 static int opt_max_connections = DEFAULT_MAX_CONN;
199 static char *opt_init_command = nullptr;
200 static bool opt_colored_diff = false;
201 static bool opt_compress = false, silent = false, verbose = false,
202 trace_exec = false;
203 static bool debug_info_flag = false, debug_check_flag = false;
204 static bool tty_password = false;
205 static bool opt_mark_progress = false;
206 static bool ps_protocol = false, ps_protocol_enabled = false;
207 static bool sp_protocol = false, sp_protocol_enabled = false;
208 static bool no_skip = false;
209 static bool skip_ignored = false;
210 static bool view_protocol = false, view_protocol_enabled = false;
211 static bool opt_trace_protocol = false, opt_trace_protocol_enabled = false;
212 static bool explain_protocol = false, explain_protocol_enabled = false;
213 static bool json_explain_protocol = false,
214 json_explain_protocol_enabled = false;
215 static bool cursor_protocol = false, cursor_protocol_enabled = false;
216 static bool testcase_disabled = false;
217 static bool display_result_vertically = false, display_result_lower = false,
218 display_metadata = false, display_result_sorted = false,
219 display_session_track_info = false;
220 static bool skip_if_hypergraph = false;
221 static int start_sort_column = 0;
222 static bool disable_query_log = false, disable_result_log = false;
223 static bool disable_connect_log = true;
224 static bool disable_warnings = false;
225 static bool disable_info = true;
226 static bool abort_on_error = true;
227 static bool server_initialized = false;
228 static bool is_windows = false;
229 static MEM_ROOT argv_alloc{PSI_NOT_INSTRUMENTED, 512};
230 static const char *load_default_groups[] = {"mysqltest", "client", nullptr};
231 static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos = line_buffer;
232 static bool can_handle_expired_passwords = true;
233 static bool opt_hypergraph = false;
234
235 /*
236 These variables control the behavior of the asynchronous operations for
237 mysqltest client. If --async-client is specified, use_async_client is true.
238 Each command checks enable_async_client (which can be forced off or
239 disabled for a single command) to decide the mode it uses to run.
240 */
241 static bool use_async_client = false;
242 static bool enable_async_client = false;
243
244 // Secondary engine options
245 static const char *opt_offload_count_file;
246
247 static Secondary_engine *secondary_engine = nullptr;
248
249 static uint opt_zstd_compress_level = default_zstd_compression_level;
250 static char *opt_compress_algorithm = nullptr;
251 static uint opt_test_ssl_fips_mode = 0;
252
253 #ifdef _WIN32
254 static DWORD opt_safe_process_pid;
255 static HANDLE mysqltest_thread;
256 // Event handle for stacktrace request event
257 static HANDLE stacktrace_request_event = NULL;
258 static std::thread wait_for_stacktrace_request_event_thread;
259 #endif
260
261 Logfile log_file;
262 // File to store the progress
263 Logfile progress_file;
264
265 /// Info on properties that can be set with '--disable_X' and
266 /// '--disable_X' commands.
267 struct Property {
268 bool *var; // Actual variable
269 bool set; // Has been set for ONCE command
270 bool old; // If set, thus is the old value
271 bool reverse; // Variable is true if disabled
272 const char *env_name; // Environment variable name
273 };
274
275 static struct Property prop_list[] = {
276 {&abort_on_error, false, true, false, "$ENABLE_ABORT_ON_ERROR"},
277 {&disable_connect_log, false, true, true, "$ENABLE_CONNECT_LOG"},
278 {&disable_info, false, true, true, "$ENABLE_INFO"},
279 {&display_session_track_info, false, true, true,
280 "$ENABLE_STATE_CHANGE_INFO"},
281 {&display_metadata, false, false, false, "$ENABLE_METADATA"},
282 {&ps_protocol_enabled, false, false, false, "$ENABLE_PS_PROTOCOL"},
283 {&disable_query_log, false, false, true, "$ENABLE_QUERY_LOG"},
284 {&disable_result_log, false, false, true, "$ENABLE_RESULT_LOG"},
285 {&disable_warnings, false, false, true, "$ENABLE_WARNINGS"},
286 {&enable_async_client, false, false, false, "$ENABLE_ASYNC_CLIENT"}};
287
288 static bool once_property = false;
289
290 enum enum_prop {
291 P_ABORT = 0,
292 P_CONNECT,
293 P_INFO,
294 P_SESSION_TRACK,
295 P_META,
296 P_PS,
297 P_QUERY,
298 P_RESULT,
299 P_WARN,
300 P_ASYNC,
301 P_MAX
302 };
303
304 static uint start_lineno = 0; /* Start line of current command */
305 static uint my_end_arg = 0;
306
307 /* Number of lines of the result to include in failure report */
308 static uint opt_tail_lines = 0;
309
310 static uint opt_connect_timeout = 0;
311
312 static char delimiter[MAX_DELIMITER_LENGTH] = ";";
313 static size_t delimiter_length = 1;
314
315 static char TMPDIR[FN_REFLEN];
316
317 /* Block stack */
318 enum block_cmd { cmd_none, cmd_if, cmd_while, cmd_assert };
319
320 struct st_block {
321 int line; /* Start line of block */
322 bool ok; /* Should block be executed */
323 enum block_cmd cmd; /* Command owning the block */
324 char delim[MAX_DELIMITER_LENGTH]; /* Delimiter before block */
325 };
326
327 static struct st_block block_stack[32];
328 static struct st_block *cur_block, *block_stack_end;
329
330 /* Open file stack */
331 struct st_test_file {
332 FILE *file;
333 char *file_name;
334 uint lineno; /* Current line in file */
335 };
336
337 static struct st_test_file file_stack[16];
338 static struct st_test_file *cur_file;
339 static struct st_test_file *file_stack_end;
340
341 static const char *default_charset = MYSQL_DEFAULT_CHARSET_NAME;
342 CHARSET_INFO *charset_info =
343 &my_charset_utf8mb4_0900_ai_ci; /* Default charset */
344
345 /*
346 Timer related variables
347 See the timer_output() definition for details
348 */
349 static char *timer_file = nullptr;
350 static ulonglong timer_start;
351 static void timer_output(void);
352 static ulonglong timer_now(void);
353
354 static ulong connection_retry_sleep = 100000; /* Microseconds */
355
356 static char *opt_plugin_dir = nullptr;
357
358 /* To retrieve a filename from a filepath */
359 3 const char *get_filename_from_path(const char *path) {
360 3 const char *fname = nullptr;
361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (is_windows)
362 fname = strrchr(path, '\\');
363 else
364 3 fname = strrchr(path, '/');
365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (fname == nullptr)
366 return path;
367 else
368 3 return ++fname;
369 }
370
371 static uint opt_protocol = 0;
372
373 #if defined(_WIN32)
374 static uint opt_protocol_for_default_connection = MYSQL_PROTOCOL_PIPE;
375 #endif
376
377 struct st_command;
378 typedef Prealloced_array<st_command *, 1024> Q_lines;
379 Q_lines *q_lines;
380
381 #include "sslopt-vars.h"
382
383 struct Parser {
384 int read_lines, current_line;
385 } parser;
386
387 struct MasterPos {
388 char file[FN_REFLEN];
389 ulong pos;
390 } master_pos;
391
392 /* if set, all results are concated and compared against this file */
393 const char *result_file_name = nullptr;
394
395 typedef struct {
396 char *name;
397 size_t name_len;
398 char *str_val;
399 size_t str_val_len;
400 int int_val;
401 size_t alloced_len;
402 bool int_dirty; /* do not update string if int is updated until first read */
403 bool is_int;
404 bool alloced;
405 } VAR;
406
407 /*Perl/shell-like variable registers */
408 VAR var_reg[10];
409
410 struct var_free {
411 void operator()(VAR *var) const;
412 };
413
414 collation_unordered_map<std::string, std::unique_ptr<VAR, var_free>> *var_hash;
415
416 struct st_connection {
417 MYSQL mysql;
418 /* Used when creating views and sp, to avoid implicit commit */
419 MYSQL *util_mysql;
420 char *name;
421 size_t name_len;
422 MYSQL_STMT *stmt;
423 /* Set after send to disallow other queries before reap */
424 bool pending;
425 };
426
427 struct st_connection *connections = nullptr;
428 struct st_connection *cur_con = nullptr, *next_con, *connections_end;
429
430 /*
431 List of commands in mysqltest
432 Must match the "command_names" array
433 Add new commands before Q_UNKNOWN!
434 */
435 enum enum_commands {
436 Q_CONNECTION = 1,
437 Q_QUERY,
438 Q_CONNECT,
439 Q_SLEEP,
440 Q_INC,
441 Q_DEC,
442 Q_SOURCE,
443 Q_DISCONNECT,
444 Q_LET,
445 Q_ECHO,
446 Q_EXPR,
447 Q_WHILE,
448 Q_END_BLOCK,
449 Q_SAVE_MASTER_POS,
450 Q_SYNC_WITH_MASTER,
451 Q_SYNC_SLAVE_WITH_MASTER,
452 Q_ERROR,
453 Q_SEND,
454 Q_REAP,
455 Q_DIRTY_CLOSE,
456 Q_REPLACE,
457 Q_REPLACE_COLUMN,
458 Q_PING,
459 Q_EVAL,
460 Q_ENABLE_QUERY_LOG,
461 Q_DISABLE_QUERY_LOG,
462 Q_ENABLE_RESULT_LOG,
463 Q_DISABLE_RESULT_LOG,
464 Q_ENABLE_CONNECT_LOG,
465 Q_DISABLE_CONNECT_LOG,
466 Q_WAIT_FOR_SLAVE_TO_STOP,
467 Q_ENABLE_WARNINGS,
468 Q_DISABLE_WARNINGS,
469 Q_ENABLE_INFO,
470 Q_DISABLE_INFO,
471 Q_ENABLE_SESSION_TRACK_INFO,
472 Q_DISABLE_SESSION_TRACK_INFO,
473 Q_ENABLE_METADATA,
474 Q_DISABLE_METADATA,
475 Q_ENABLE_ASYNC_CLIENT,
476 Q_DISABLE_ASYNC_CLIENT,
477 Q_EXEC,
478 Q_EXECW,
479 Q_EXEC_BACKGROUND,
480 Q_DELIMITER,
481 Q_DISABLE_ABORT_ON_ERROR,
482 Q_ENABLE_ABORT_ON_ERROR,
483 Q_DISPLAY_VERTICAL_RESULTS,
484 Q_DISPLAY_HORIZONTAL_RESULTS,
485 Q_QUERY_VERTICAL,
486 Q_QUERY_HORIZONTAL,
487 Q_SORTED_RESULT,
488 Q_PARTIALLY_SORTED_RESULT,
489 Q_LOWERCASE,
490 Q_SKIP_IF_HYPERGRAPH,
491 Q_START_TIMER,
492 Q_END_TIMER,
493 Q_CHARACTER_SET,
494 Q_DISABLE_PS_PROTOCOL,
495 Q_ENABLE_PS_PROTOCOL,
496 Q_DISABLE_RECONNECT,
497 Q_ENABLE_RECONNECT,
498 Q_IF,
499 Q_DISABLE_TESTCASE,
500 Q_ENABLE_TESTCASE,
501 Q_REPLACE_REGEX,
502 Q_REPLACE_NUMERIC_ROUND,
503 Q_REMOVE_FILE,
504 Q_FILE_EXIST,
505 Q_WRITE_FILE,
506 Q_COPY_FILE,
507 Q_PERL,
508 Q_DIE,
509 Q_ASSERT,
510 Q_EXIT,
511 Q_SKIP,
512 Q_CHMOD_FILE,
513 Q_APPEND_FILE,
514 Q_CAT_FILE,
515 Q_DIFF_FILES,
516 Q_SEND_QUIT,
517 Q_CHANGE_USER,
518 Q_MKDIR,
519 Q_RMDIR,
520 Q_FORCE_RMDIR,
521 Q_FORCE_CPDIR,
522 Q_LIST_FILES,
523 Q_LIST_FILES_WRITE_FILE,
524 Q_LIST_FILES_APPEND_FILE,
525 Q_SEND_SHUTDOWN,
526 Q_SHUTDOWN_SERVER,
527 Q_RESULT_FORMAT_VERSION,
528 Q_MOVE_FILE,
529 Q_REMOVE_FILES_WILDCARD,
530 Q_COPY_FILES_WILDCARD,
531 Q_SEND_EVAL,
532 Q_OUTPUT, /* redirect output to a file */
533 Q_RESET_CONNECTION,
534 Q_QUERY_ATTRIBUTES,
535 Q_UNKNOWN, /* Unknown command. */
536 Q_COMMENT, /* Comments, ignored. */
537 Q_COMMENT_WITH_COMMAND,
538 Q_EMPTY_LINE
539 };
540
541 const char *command_names[] = {
542 "connection", "query", "connect", "sleep", "inc", "dec", "source",
543 "disconnect", "let", "echo", "expr", "while", "end", "save_master_pos",
544 "sync_with_master", "sync_slave_with_master", "error", "send", "reap",
545 "dirty_close", "replace_result", "replace_column", "ping", "eval",
546 /* Enable/disable that the _query_ is logged to result file */
547 "enable_query_log", "disable_query_log",
548 /* Enable/disable that the _result_ from a query is logged to result file */
549 "enable_result_log", "disable_result_log", "enable_connect_log",
550 "disable_connect_log", "wait_for_slave_to_stop", "enable_warnings",
551 "disable_warnings", "enable_info", "disable_info",
552 "enable_session_track_info", "disable_session_track_info",
553 "enable_metadata", "disable_metadata", "enable_async_client",
554 "disable_async_client", "exec", "execw", "exec_in_background", "delimiter",
555 "disable_abort_on_error", "enable_abort_on_error", "vertical_results",
556 "horizontal_results", "query_vertical", "query_horizontal", "sorted_result",
557 "partially_sorted_result", "lowercase_result", "skip_if_hypergraph",
558 "start_timer", "end_timer", "character_set", "disable_ps_protocol",
559 "enable_ps_protocol", "disable_reconnect", "enable_reconnect", "if",
560 "disable_testcase", "enable_testcase", "replace_regex",
561 "replace_numeric_round", "remove_file", "file_exists", "write_file",
562 "copy_file", "perl", "die", "assert",
563
564 /* Don't execute any more commands, compare result */
565 "exit", "skip", "chmod", "append_file", "cat_file", "diff_files",
566 "send_quit", "change_user", "mkdir", "rmdir", "force-rmdir", "force-cpdir",
567 "list_files", "list_files_write_file", "list_files_append_file",
568 "send_shutdown", "shutdown_server", "result_format", "move_file",
569 "remove_files_wildcard", "copy_files_wildcard", "send_eval", "output",
570 "reset_connection", "query_attributes",
571
572 nullptr};
573
574 struct st_command {
575 char *query, *query_buf, *first_argument, *last_argument, *end;
576 DYNAMIC_STRING content;
577 size_t first_word_len, query_len;
578 bool abort_on_error, used_replace;
579 char output_file[FN_REFLEN];
580 enum enum_commands type;
581 // Line number of the command
582 uint lineno;
583 };
584
585 TYPELIB command_typelib = {array_elements(command_names), "", command_names,
586 nullptr};
587
588 DYNAMIC_STRING ds_res;
589 DYNAMIC_STRING ds_result;
590 /* Points to ds_warning in run_query, so it can be freed */
591 DYNAMIC_STRING *ds_warn = nullptr;
592 struct st_command *curr_command = nullptr;
593
594 char builtin_echo[FN_REFLEN];
595
596 /* Stores regex substitutions */
597
598 struct st_replace_regex *glob_replace_regex = nullptr;
599
600 struct REPLACE;
601 REPLACE *glob_replace = nullptr;
602 void replace_strings_append(REPLACE *rep, DYNAMIC_STRING *ds, const char *from,
603 size_t len);
604
605 static void cleanup_and_exit(int exit_code) MY_ATTRIBUTE((noreturn));
606
607 void die(const char *fmt, ...) MY_ATTRIBUTE((format(printf, 1, 2)))
608 MY_ATTRIBUTE((noreturn));
609 void abort_not_supported_test(const char *fmt, ...)
610 MY_ATTRIBUTE((format(printf, 1, 2))) MY_ATTRIBUTE((noreturn));
611 void verbose_msg(const char *fmt, ...) MY_ATTRIBUTE((format(printf, 1, 2)));
612 void log_msg(const char *fmt, ...) MY_ATTRIBUTE((format(printf, 1, 2)));
613 void flush_ds_res();
614
615 VAR *var_from_env(const char *, const char *);
616 VAR *var_init(VAR *v, const char *name, size_t name_len, const char *val,
617 size_t val_len);
618 VAR *var_get(const char *var_name, const char **var_name_end, bool raw,
619 bool ignore_not_existing);
620 void eval_expr(VAR *v, const char *p, const char **p_end, bool open_end = false,
621 bool do_eval = true);
622 bool match_delimiter(int c, const char *delim, size_t length);
623
624 void do_eval(DYNAMIC_STRING *query_eval, const char *query,
625 const char *query_end, bool pass_through_escape_chars);
626 void str_to_file(const char *fname, char *str, size_t size);
627 void str_to_file2(const char *fname, char *str, size_t size, bool append);
628
629 void fix_win_paths(const char *val, size_t len);
630
631 #ifdef _WIN32
632 void free_win_path_patterns();
633 #endif
634
635 /* For replace_column */
636 static char *replace_column[MAX_COLUMNS];
637 static uint max_replace_column = 0;
638 void do_get_replace_column(struct st_command *);
639 void free_replace_column();
640
641 static void do_query_attributes(struct st_command *command);
642
643 /* For replace */
644 void do_get_replace(struct st_command *command);
645 void free_replace();
646
647 /* For replace_regex */
648 void do_get_replace_regex(struct st_command *command);
649 void free_replace_regex();
650
651 /* For replace numeric round */
652 static int glob_replace_numeric_round = -1;
653 void do_get_replace_numeric_round(struct st_command *command);
654 void free_replace_numeric_round();
655 void replace_numeric_round_append(int round, DYNAMIC_STRING *ds,
656 const char *from, size_t len);
657
658 /* Used by sleep */
659 void check_eol_junk_line(const char *eol);
660
661 static void var_set(const char *var_name, const char *var_name_end,
662 const char *var_val, const char *var_val_end);
663
664 6265376 static void free_all_replace() {
665 6265376 free_replace();
666 6265376 free_replace_regex();
667 6265376 free_replace_column();
668 6265376 free_replace_numeric_round();
669 6265376 global_attrs->clear();
670 6265376 }
671
672 /*
673 To run tests via the async API, invoke mysqltest with --async-client.
674 */
675 class AsyncTimer {
676 public:
677 823 explicit AsyncTimer(std::string label)
678 823 : label_(label), time_(std::chrono::system_clock::now()), start_(time_) {}
679
680 823 ~AsyncTimer() {
681 823 auto now = std::chrono::system_clock::now();
682 823 auto delta = now - start_;
683 [[maybe_unused]] ulonglong micros =
684 823 std::chrono::duration_cast<std::chrono::microseconds>(delta).count();
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 823 times.
823 DBUG_PRINT("async_timing",
686 ("%s total micros: %llu", label_.c_str(), micros));
687 823 }
688
689 29925177 void check() {
690 29925177 auto now = std::chrono::system_clock::now();
691
1/2
✓ Branch 0 taken 29925177 times.
✗ Branch 1 not taken.
29925177 auto delta = now - time_;
692 29925177 time_ = now;
693 [[maybe_unused]] ulonglong micros =
694
1/2
✓ Branch 0 taken 29925177 times.
✗ Branch 1 not taken.
29925177 std::chrono::duration_cast<std::chrono::microseconds>(delta).count();
695
3/8
✓ Branch 0 taken 29925177 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29925177 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 29925177 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
29925177 DBUG_PRINT("async_timing", ("%s op micros: %llu", label_.c_str(), micros));
696 29925177 }
697
698 private:
699 std::string label_;
700 std::chrono::system_clock::time_point time_;
701 std::chrono::system_clock::time_point start_;
702 };
703
704 #ifdef _WIN32
705 /*
706 Check if any data is available in the socket to be read or written.
707 */
708 static int socket_event_listen(my_socket fd) {
709 int result;
710 fd_set readfds, writefds, exceptfds;
711
712 FD_ZERO(&readfds);
713 FD_ZERO(&writefds);
714 FD_ZERO(&exceptfds);
715
716 FD_SET(fd, &exceptfds);
717 FD_SET(fd, &readfds);
718 FD_SET(fd, &writefds);
719
720 result = select((int)(fd + 1), &readfds, &writefds, &exceptfds, NULL);
721 if (result < 0) {
722 DWORD error_code = WSAGetLastError();
723 verbose_msg("Cannot determine the status due to error :%lu\n", error_code);
724 }
725 return result;
726 }
727 #else
728 29838881 static int socket_event_listen(my_socket fd) {
729 int result;
730 pollfd pfd;
731 29838881 pfd.fd = fd;
732 /*
733 Listen to both in/out because SSL can perform reads during writes (and
734 vice versa).
735 */
736 29838881 pfd.events = POLLIN | POLLOUT;
737
1/2
✓ Branch 0 taken 29838881 times.
✗ Branch 1 not taken.
29838881 result = poll(&pfd, 1, -1);
738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29838881 times.
29838881 if (result < 0) {
739 perror("poll");
740 }
741 29838881 return result;
742 }
743 #endif
744
745 /*
746 Below async_mysql_*_wrapper functions are used to measure how much time
747 each nonblocking call spends before completing the operations.
748 i*/
749 206 static MYSQL_ROW async_mysql_fetch_row_wrapper(MYSQL_RES *res) {
750 MYSQL_ROW row;
751 206 MYSQL *mysql = res->handle;
752
2/4
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
✗ Branch 3 not taken.
412 AsyncTimer t(__func__);
753
2/4
✓ Branch 0 taken 206 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 206 times.
206 while (mysql_fetch_row_nonblocking(res, &row) == NET_ASYNC_NOT_READY) {
754 t.check();
755 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
756 if (result == -1) return nullptr;
757 }
758 206 return row;
759 206 }
760
761 110 static MYSQL_RES *async_mysql_store_result_wrapper(MYSQL *mysql) {
762 MYSQL_RES *mysql_result;
763
2/4
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
220 AsyncTimer t(__func__);
764
3/4
✓ Branch 0 taken 163526 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163416 times.
✓ Branch 3 taken 110 times.
163526 while (mysql_store_result_nonblocking(mysql, &mysql_result) ==
765 NET_ASYNC_NOT_READY) {
766
1/2
✓ Branch 0 taken 163416 times.
✗ Branch 1 not taken.
163416 t.check();
767
2/4
✓ Branch 0 taken 163416 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163416 times.
✗ Branch 3 not taken.
163416 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 163416 times.
163416 if (result == -1) return nullptr;
769 }
770 110 return mysql_result;
771 110 }
772
773 20 static int async_mysql_real_query_wrapper(MYSQL *mysql, const char *query,
774 ulong length) {
775 net_async_status status;
776
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
40 AsyncTimer t(__func__);
777
3/4
✓ Branch 0 taken 5227520 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5227500 times.
✓ Branch 3 taken 20 times.
5227520 while ((status = mysql_real_query_nonblocking(mysql, query, length)) ==
778 NET_ASYNC_NOT_READY) {
779
1/2
✓ Branch 0 taken 5227500 times.
✗ Branch 1 not taken.
5227500 t.check();
780
2/4
✓ Branch 0 taken 5227500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5227500 times.
✗ Branch 3 not taken.
5227500 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
781
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5227500 times.
5227500 if (result == -1) return 1;
782 }
783
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (status == NET_ASYNC_ERROR) {
784 return 1;
785 }
786 20 return 0;
787 20 }
788
789 112 static int async_mysql_send_query_wrapper(MYSQL *mysql, const char *query,
790 ulong length) {
791 net_async_status status;
792
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
224 AsyncTimer t(__func__);
793
3/4
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 112 times.
169 while ((status = mysql_send_query_nonblocking(mysql, query, length)) ==
794 NET_ASYNC_NOT_READY) {
795
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 t.check();
796
2/4
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
57 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (result == -1) return 1;
798 }
799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (status == NET_ASYNC_ERROR) {
800 return 1;
801 }
802 112 return 0;
803 112 }
804
805 112 static bool async_mysql_read_query_result_wrapper(MYSQL *mysql) {
806 net_async_status status;
807
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
224 AsyncTimer t(__func__);
808
3/4
✓ Branch 0 taken 24448020 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24447908 times.
✓ Branch 3 taken 112 times.
24448020 while ((status = (*mysql->methods->read_query_result_nonblocking)(mysql)) ==
809 NET_ASYNC_NOT_READY) {
810
1/2
✓ Branch 0 taken 24447908 times.
✗ Branch 1 not taken.
24447908 t.check();
811
2/4
✓ Branch 0 taken 24447908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24447908 times.
✗ Branch 3 not taken.
24447908 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
812
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24447908 times.
24447908 if (result == -1) return true;
813 }
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (status == NET_ASYNC_ERROR) {
815 return true;
816 }
817 112 return false;
818 112 }
819
820 112 static int async_mysql_next_result_wrapper(MYSQL *mysql) {
821 net_async_status status;
822
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
224 AsyncTimer t(__func__);
823
2/4
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
112 while ((status = mysql_next_result_nonblocking(mysql)) ==
824 NET_ASYNC_NOT_READY) {
825 t.check();
826 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
827 if (result == -1) return 1;
828 }
829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
112 if (status == NET_ASYNC_ERROR)
830 return 1;
831
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 else if (status == NET_ASYNC_COMPLETE_NO_MORE_RESULTS)
832 112 return -1;
833 else
834 return 0;
835 112 }
836
837 41 static MYSQL *async_mysql_real_connect_wrapper(
838 MYSQL *mysql, const char *host, const char *user, const char *passwd,
839 const char *db, uint port, const char *unix_socket, ulong client_flag) {
840 net_async_status status;
841
2/4
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
82 AsyncTimer t(__func__);
842
843
1/2
✓ Branch 0 taken 86337 times.
✗ Branch 1 not taken.
86337 while ((status = mysql_real_connect_nonblocking(
844
2/2
✓ Branch 0 taken 86296 times.
✓ Branch 1 taken 41 times.
86337 mysql, host, user, passwd, db, port, unix_socket, client_flag)) ==
845 NET_ASYNC_NOT_READY) {
846
1/2
✓ Branch 0 taken 86296 times.
✗ Branch 1 not taken.
86296 t.check();
847 }
848
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 32 times.
41 if (status == NET_ASYNC_ERROR)
849 9 return nullptr;
850 else
851 32 return mysql;
852 41 }
853
854 static int async_mysql_query_wrapper(MYSQL *mysql, const char *query) {
855 net_async_status status;
856 AsyncTimer t(__func__);
857 while ((status = mysql_real_query_nonblocking(mysql, query, strlen(query))) ==
858 NET_ASYNC_NOT_READY) {
859 t.check();
860 int result = socket_event_listen(mysql_get_socket_descriptor(mysql));
861 if (result == -1) return 1;
862 }
863 if (status == NET_ASYNC_ERROR) {
864 return 1;
865 }
866 return 0;
867 }
868
869 110 static void async_mysql_free_result_wrapper(MYSQL_RES *result) {
870
2/4
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
✗ Branch 3 not taken.
220 AsyncTimer t(__func__);
871
2/4
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 110 times.
110 while (mysql_free_result_nonblocking(result) == NET_ASYNC_NOT_READY) {
872 t.check();
873 MYSQL *mysql = result->handle;
874 int listen_result = socket_event_listen(mysql_get_socket_descriptor(mysql));
875 if (listen_result == -1) return;
876 }
877 110 return;
878 110 }
879
880 /*
881 Below are the wrapper functions which are defined on top of standard C APIs
882 to make a decision on whether to call blocking or non blocking API based on
883 --async-client option is set or not.
884 */
885 60796533 static MYSQL_ROW mysql_fetch_row_wrapper(MYSQL_RES *res) {
886
2/2
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 60796327 times.
60796533 if (enable_async_client)
887 206 return async_mysql_fetch_row_wrapper(res);
888 else
889 60796327 return mysql_fetch_row(res);
890 }
891
892 8815145 static MYSQL_RES *mysql_store_result_wrapper(MYSQL *mysql) {
893
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 8815035 times.
8815145 if (enable_async_client)
894 110 return async_mysql_store_result_wrapper(mysql);
895 else
896 8815035 return mysql_store_result(mysql);
897 }
898
899 7660644 static int mysql_real_query_wrapper(MYSQL *mysql, const char *query,
900 ulong length) {
901 int rc;
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7660644 times.
7660644 if (0 != (rc = global_attrs->set_params(mysql))) return rc;
903
904
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 7660624 times.
7660644 if (enable_async_client)
905 20 return async_mysql_real_query_wrapper(mysql, query, length);
906 else
907 7660624 return mysql_real_query(mysql, query, length);
908 }
909
910 4119135 static int mysql_send_query_wrapper(MYSQL *mysql, const char *query,
911 ulong length) {
912 int rc;
913
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4119135 times.
4119135 if (0 != (rc = global_attrs->set_params(mysql))) return rc;
914
915
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 4119023 times.
4119135 if (enable_async_client)
916 112 return async_mysql_send_query_wrapper(mysql, query, length);
917 else
918 4119023 return mysql_send_query(mysql, query, length);
919 }
920
921 3807254 static bool mysql_read_query_result_wrapper(MYSQL *mysql) {
922 bool ret;
923
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 3807142 times.
3807254 if (enable_async_client)
924 112 ret = async_mysql_read_query_result_wrapper(mysql);
925 else
926 3807142 ret = mysql_read_query_result(mysql);
927 3807254 return ret;
928 }
929
930 9444 static int mysql_query_wrapper(MYSQL *mysql, const char *query) {
931 int rc;
932
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9444 times.
9444 if (0 != (rc = global_attrs->set_params(mysql))) return rc;
933
934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9444 times.
9444 if (enable_async_client)
935 return async_mysql_query_wrapper(mysql, query);
936 else
937 9444 return mysql_query(mysql, query);
938 }
939
940 4484598 static int mysql_next_result_wrapper(MYSQL *mysql) {
941
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 4484486 times.
4484598 if (enable_async_client)
942 112 return async_mysql_next_result_wrapper(mysql);
943 else
944 4484486 return mysql_next_result(mysql);
945 }
946
947 96351 static MYSQL *mysql_real_connect_wrapper(MYSQL *mysql, const char *host,
948 const char *user, const char *passwd,
949 const char *db, uint port,
950 const char *unix_socket,
951 ulong client_flag) {
952
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 96310 times.
96351 if (enable_async_client)
953 41 return async_mysql_real_connect_wrapper(mysql, host, user, passwd, db, port,
954 41 unix_socket, client_flag);
955 else
956 96310 return mysql_real_connect(mysql, host, user, passwd, db, port, unix_socket,
957 96310 client_flag);
958 }
959
960 8811234 static void mysql_free_result_wrapper(MYSQL_RES *result) {
961
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 8811124 times.
8811234 if (enable_async_client)
962 110 return async_mysql_free_result_wrapper(result);
963 else
964 8811124 return mysql_free_result(result);
965 }
966
967 /* async client test code (end) */
968
969 void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, size_t len);
970 void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val);
971 void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val);
972 void dynstr_append_sorted(DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_input,
973 int start_sort_column);
974
975 void revert_properties();
976
977 51792011 void do_eval(DYNAMIC_STRING *query_eval, const char *query,
978 const char *query_end, bool pass_through_escape_chars) {
979 const char *p;
980 char c, next_c;
981 51792011 int escaped = 0;
982 VAR *v;
983
1/2
✓ Branch 0 taken 51792011 times.
✗ Branch 1 not taken.
51792011 DBUG_TRACE;
984
985
6/6
✓ Branch 0 taken 1881185161 times.
✓ Branch 1 taken 43379889 times.
✓ Branch 2 taken 1872773039 times.
✓ Branch 3 taken 8412122 times.
✓ Branch 4 taken 1872773039 times.
✓ Branch 5 taken 51792011 times.
1924565050 for (p = query; (c = *p) && p < query_end; ++p) {
986 1872773039 next_c = *(p + 1);
987
3/3
✓ Branch 0 taken 23261352 times.
✓ Branch 1 taken 625314 times.
✓ Branch 2 taken 1848886373 times.
1872773039 switch (c) {
988 23261352 case '$':
989
4/4
✓ Branch 0 taken 23193819 times.
✓ Branch 1 taken 67533 times.
✓ Branch 2 taken 23146107 times.
✓ Branch 3 taken 47712 times.
23261352 if (escaped ||
990 // a JSON path expression
991
5/6
✓ Branch 0 taken 23142623 times.
✓ Branch 1 taken 3484 times.
✓ Branch 2 taken 23142593 times.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 23142593 times.
23146107 next_c == '.' || next_c == '[' || next_c == '\'' || next_c == '"') {
992 118759 escaped = 0;
993
1/2
✓ Branch 0 taken 118759 times.
✗ Branch 1 not taken.
118759 dynstr_append_mem(query_eval, p, 1);
994 } else {
995
2/4
✓ Branch 0 taken 23142593 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23142593 times.
23142593 if (!(v = var_get(p, &p, false, false))) die("Bad variable in eval");
996
1/2
✓ Branch 0 taken 23142593 times.
✗ Branch 1 not taken.
23142593 dynstr_append_mem(query_eval, v->str_val, v->str_val_len);
997 }
998 23261352 break;
999 625314 case '\\':
1000
2/2
✓ Branch 0 taken 2332 times.
✓ Branch 1 taken 622982 times.
625314 if (escaped) {
1001 2332 escaped = 0;
1002
1/2
✓ Branch 0 taken 2332 times.
✗ Branch 1 not taken.
2332 dynstr_append_mem(query_eval, p, 1);
1003
6/6
✓ Branch 0 taken 620650 times.
✓ Branch 1 taken 2332 times.
✓ Branch 2 taken 553117 times.
✓ Branch 3 taken 67533 times.
✓ Branch 4 taken 946 times.
✓ Branch 5 taken 552171 times.
622982 } else if (next_c == '\\' || next_c == '$' || next_c == '"') {
1004 /* Set escaped only if next char is \, " or $ */
1005 70811 escaped = 1;
1006
1007
2/2
✓ Branch 0 taken 309 times.
✓ Branch 1 taken 70502 times.
70811 if (pass_through_escape_chars) {
1008 /* The escape char should be added to the output string. */
1009
1/2
✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
309 dynstr_append_mem(query_eval, p, 1);
1010 }
1011 } else
1012
1/2
✓ Branch 0 taken 552171 times.
✗ Branch 1 not taken.
552171 dynstr_append_mem(query_eval, p, 1);
1013 625314 break;
1014 1848886373 default:
1015 1848886373 escaped = 0;
1016
1/2
✓ Branch 0 taken 1848886373 times.
✗ Branch 1 not taken.
1848886373 dynstr_append_mem(query_eval, p, 1);
1017 1848886373 break;
1018 }
1019 }
1020 #ifdef _WIN32
1021 fix_win_paths(query_eval->str, query_eval->length);
1022 #endif
1023 51792011 }
1024
1025 /*
1026 Run query and dump the result to stderr in vertical format
1027
1028 NOTE! This function should be safe to call when an error
1029 has occurred and thus any further errors will be ignored(although logged)
1030
1031 SYNOPSIS
1032 show_query
1033 mysql - connection to use
1034 query - query to run
1035
1036 */
1037
1038 6 static void show_query(MYSQL *mysql, const char *query) {
1039 MYSQL_RES *res;
1040
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 DBUG_TRACE;
1041
1042
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!mysql) return;
1043
1044
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (mysql_query_wrapper(mysql, query)) {
1045 log_msg("Error running query '%s': %d %s", query, mysql_errno(mysql),
1046 mysql_error(mysql));
1047 return;
1048 }
1049
1050
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if ((res = mysql_store_result_wrapper(mysql)) == nullptr) {
1051 /* No result set returned */
1052 return;
1053 }
1054
1055 {
1056 MYSQL_ROW row;
1057 unsigned int i;
1058 6 unsigned int row_num = 0;
1059
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 unsigned int num_fields = mysql_num_fields(res);
1060
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 MYSQL_FIELD *fields = mysql_fetch_fields(res);
1061
1062
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 fprintf(stderr, "=== %s ===\n", query);
1063
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 6 times.
24 while ((row = mysql_fetch_row_wrapper(res))) {
1064
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 unsigned long *lengths = mysql_fetch_lengths(res);
1065 18 row_num++;
1066
1067
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 fprintf(stderr, "---- %d. ----\n", row_num);
1068
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 18 times.
216 for (i = 0; i < num_fields; i++) {
1069 /* looks ugly , but put here to convince parfait */
1070
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 assert(lengths);
1071
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
198 fprintf(stderr, "%s\t%.*s\n", fields[i].name, (int)lengths[i],
1072
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 18 times.
198 row[i] ? row[i] : "NULL");
1073 }
1074 }
1075
3/4
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 144 times.
✓ Branch 3 taken 6 times.
150 for (i = 0; i < std::strlen(query) + 8; i++) fprintf(stderr, "=");
1076
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 fprintf(stderr, "\n\n");
1077 }
1078
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 mysql_free_result_wrapper(res);
1079
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 }
1080
1081 /*
1082 Show any warnings just before the error. Since the last error
1083 is added to the warning stack, only print @@warning_count-1 warnings.
1084
1085 NOTE! This function should be safe to call when an error
1086 has occurred and this any further errors will be ignored(although logged)
1087
1088 SYNOPSIS
1089 show_warnings_before_error
1090 mysql - connection to use
1091
1092 */
1093
1094 732 static void show_warnings_before_error(MYSQL *mysql) {
1095 MYSQL_RES *res;
1096 732 const char *query = "SHOW WARNINGS";
1097
1/2
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
732 DBUG_TRACE;
1098
1099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 732 times.
732 if (!mysql) return;
1100
1101
3/4
✓ Branch 0 taken 732 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 728 times.
732 if (mysql_query_wrapper(mysql, query)) {
1102
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
4 log_msg("Error running query '%s': %d %s", query, mysql_errno(mysql),
1103 mysql_error(mysql));
1104 4 return;
1105 }
1106
1107
2/4
✓ Branch 0 taken 728 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 728 times.
728 if ((res = mysql_store_result_wrapper(mysql)) == nullptr) {
1108 /* No result set returned */
1109 return;
1110 }
1111
1112
2/4
✓ Branch 0 taken 728 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 728 times.
728 if (mysql_num_rows(res) <= 1) {
1113 /* Don't display the last row, it's "last error" */
1114 } else {
1115 MYSQL_ROW row;
1116 unsigned int row_num = 0;
1117 unsigned int num_fields = mysql_num_fields(res);
1118
1119 fprintf(stderr, "\nWarnings from just before the error:\n");
1120 while ((row = mysql_fetch_row_wrapper(res))) {
1121 unsigned int i;
1122 unsigned long *lengths = mysql_fetch_lengths(res);
1123
1124 if (++row_num >= mysql_num_rows(res)) {
1125 /* Don't display the last row, it's "last error" */
1126 break;
1127 }
1128
1129 for (i = 0; i < num_fields; i++) {
1130 /* looks ugly , but put here to convince parfait */
1131 assert(lengths);
1132 fprintf(stderr, "%.*s ", (int)lengths[i], row[i] ? row[i] : "NULL");
1133 }
1134 fprintf(stderr, "\n");
1135 }
1136 }
1137
1/2
✓ Branch 0 taken 728 times.
✗ Branch 1 not taken.
728 mysql_free_result_wrapper(res);
1138
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 4 times.
732 }
1139
1140 enum arg_type { ARG_STRING, ARG_REST };
1141
1142 struct command_arg {
1143 const char *argname; /* Name of argument */
1144 enum arg_type type; /* Type of argument */
1145 bool required; /* Argument required */
1146 DYNAMIC_STRING *ds; /* Storage for argument */
1147 const char *description; /* Description of the argument */
1148 };
1149
1150 21452284 static void check_command_args(struct st_command *command, char *arguments,
1151 const struct command_arg *args, int num_args,
1152 const char delimiter_arg) {
1153 int i;
1154 21452284 char *ptr = arguments;
1155 const char *start;
1156
1/2
✓ Branch 0 taken 21452284 times.
✗ Branch 1 not taken.
21452284 DBUG_TRACE;
1157
3/8
✓ Branch 0 taken 21452284 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21452284 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21452284 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
21452284 DBUG_PRINT("enter", ("num_args: %d", num_args));
1158
1159
2/2
✓ Branch 0 taken 23244208 times.
✓ Branch 1 taken 21452218 times.
44696426 for (i = 0; i < num_args; i++) {
1160 23244208 const struct command_arg *arg = &args[i];
1161 char delimiter;
1162
1163
1/3
✓ Branch 0 taken 23244208 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
23244208 switch (arg->type) {
1164 /* A string */
1165 23244208 case ARG_STRING:
1166 /* Skip leading spaces */
1167
4/4
✓ Branch 0 taken 22295495 times.
✓ Branch 1 taken 2001375 times.
✓ Branch 2 taken 1052662 times.
✓ Branch 3 taken 21242833 times.
24296870 while (*ptr && *ptr == ' ') ptr++;
1168 23244208 start = ptr;
1169 23244208 delimiter = delimiter_arg;
1170 /* If start of arg is ' ` or " search to matching quote end instead */
1171
4/4
✓ Branch 0 taken 21242833 times.
✓ Branch 1 taken 2001375 times.
✓ Branch 2 taken 16289 times.
✓ Branch 3 taken 21226544 times.
23244208 if (*ptr && strchr("'`\"", *ptr)) {
1172 16289 delimiter = *ptr;
1173 16289 start = ++ptr;
1174 }
1175 /* Find end of arg, terminated by "delimiter" */
1176
4/4
✓ Branch 0 taken 519472980 times.
✓ Branch 1 taken 22029504 times.
✓ Branch 2 taken 518258276 times.
✓ Branch 3 taken 1214704 times.
541502484 while (*ptr && *ptr != delimiter) ptr++;
1177
2/2
✓ Branch 0 taken 21184231 times.
✓ Branch 1 taken 2059977 times.
23244208 if (ptr > start) {
1178
1/2
✓ Branch 0 taken 21184231 times.
✗ Branch 1 not taken.
21184231 init_dynamic_string(arg->ds, nullptr, ptr - start);
1179
1/2
✓ Branch 0 taken 21184231 times.
✗ Branch 1 not taken.
21184231 do_eval(arg->ds, start, ptr, false);
1180 } else {
1181 /* Empty string */
1182
1/2
✓ Branch 0 taken 2059977 times.
✗ Branch 1 not taken.
2059977 init_dynamic_string(arg->ds, "", 0);
1183 }
1184 /* Find real end of arg, terminated by "delimiter_arg" */
1185 /* This will do nothing if arg was not closed by quotes */
1186
4/4
✓ Branch 0 taken 1230149 times.
✓ Branch 1 taken 22030427 times.
✓ Branch 2 taken 16368 times.
✓ Branch 3 taken 1213781 times.
23260576 while (*ptr && *ptr != delimiter_arg) ptr++;
1187
1188 23244208 command->last_argument = ptr;
1189
1190 /* Step past the delimiter */
1191
3/4
✓ Branch 0 taken 1213781 times.
✓ Branch 1 taken 22030427 times.
✓ Branch 2 taken 1213781 times.
✗ Branch 3 not taken.
23244208 if (*ptr && *ptr == delimiter_arg) ptr++;
1192
3/8
✓ Branch 0 taken 23244208 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23244208 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23244208 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
23244208 DBUG_PRINT("info", ("val: %s", arg->ds->str));
1193 23244208 break;
1194
1195 /* Rest of line */
1196 case ARG_REST:
1197 start = ptr;
1198 init_dynamic_string(arg->ds, nullptr, command->query_len);
1199 do_eval(arg->ds, start, command->end, false);
1200 command->last_argument = command->end;
1201 DBUG_PRINT("info", ("val: %s", arg->ds->str));
1202 break;
1203
1204 default:
1205 assert("Unknown argument type");
1206 break;
1207 }
1208
1209 /* Check required arg */
1210
4/4
✓ Branch 0 taken 2060124 times.
✓ Branch 1 taken 21184084 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 2060058 times.
23244208 if (arg->ds->length == 0 && arg->required)
1211 66 die("Missing required argument '%s' to command '%.*s'", arg->argname,
1212 66 static_cast<int>(command->first_word_len), command->query);
1213 }
1214 /* Check for too many arguments passed */
1215 21452218 ptr = command->last_argument;
1216
4/4
✓ Branch 0 taken 21833758 times.
✓ Branch 1 taken 21452141 times.
✓ Branch 2 taken 21833696 times.
✓ Branch 3 taken 62 times.
43285899 while (ptr <= command->end && *ptr != '#') {
1217
4/4
✓ Branch 0 taken 468 times.
✓ Branch 1 taken 21833228 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 453 times.
21833696 if (*ptr && *ptr != ' ')
1218 15 die("Extra argument '%s' passed to '%.*s'", ptr,
1219 15 static_cast<int>(command->first_word_len), command->query);
1220 21833681 ptr++;
1221 }
1222 21452203 }
1223
1224 /// Check whether given error is in list of expected errors.
1225 ///
1226 /// @param command Pointer to the st_command structure which holds the
1227 /// arguments and information for the command.
1228 /// @param err_errno Error number of the error that actually occurred.
1229 /// @param err_sqlstate SQLSTATE that was thrown, or NULL for impossible
1230 /// (file-ops, diff, etc.)
1231 ///
1232 /// @retval -1 if the given error is not in the list, index in the
1233 /// list of expected errors otherwise.
1234 ///
1235 /// @note
1236 /// If caller needs to know whether the list was empty, they should
1237 /// check the value of expected_errors.count.
1238 561660 static int match_expected_error(struct st_command *command,
1239 std::uint32_t err_errno,
1240 const char *err_sqlstate) {
1241 561660 std::uint8_t index = 0;
1242
1243 // Iterator for list/vector of expected errors
1244 std::vector<std::unique_ptr<Error>>::iterator error =
1245 561660 expected_errors->begin();
1246
1247 // Iterate over list of expected errors
1248
2/2
✓ Branch 0 taken 2253875 times.
✓ Branch 1 taken 2971 times.
2256846 for (; error != expected_errors->end(); error++) {
1249
2/2
✓ Branch 0 taken 2253839 times.
✓ Branch 1 taken 36 times.
2253875 if ((*error)->type() == ERR_ERRNO) {
1250 // Error type is ERR_ERRNO
1251
2/2
✓ Branch 0 taken 558659 times.
✓ Branch 1 taken 1695180 times.
2253839 if ((*error)->error_code() == err_errno) return index;
1252
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 } else if ((*error)->type() == ERR_SQLSTATE) {
1253 // Error type is ERR_SQLSTATE. NULL is quite likely, but not in
1254 // conjunction with a SQL-state expect.
1255
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 33 times.
36 if (unlikely(err_sqlstate == nullptr)) {
1256 3 die("Expecting a SQLSTATE (%s) from query '%s' which cannot produce "
1257 "one.",
1258 3 (*error)->sqlstate(), command->query);
1259 }
1260
1261
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 6 times.
33 if (!std::strncmp((*error)->sqlstate(), err_sqlstate, SQLSTATE_LENGTH))
1262 27 return index;
1263 }
1264
1265 1695186 index++;
1266 }
1267
1268 2971 return -1;
1269 }
1270
1271 /// Handle errors which occurred during execution of a query.
1272 ///
1273 /// @param command Pointer to the st_command structure which holds the
1274 /// arguments and information for the command.
1275 /// @param err_errno Error number
1276 /// @param err_error Error message
1277 /// @param err_sqlstate SQLSTATE that was thrown
1278 /// @param ds Dynamic string to store the result.
1279 ///
1280 /// @note
1281 /// If there is an unexpected error, this function will abort mysqltest
1282 /// immediately.
1283 400537 void handle_error(struct st_command *command, std::uint32_t err_errno,
1284 const char *err_error, const char *err_sqlstate,
1285 DYNAMIC_STRING *ds) {
1286
1/2
✓ Branch 0 taken 400537 times.
✗ Branch 1 not taken.
400537 DBUG_TRACE;
1287
1288
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 400537 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
400537 if (opt_hypergraph && err_errno == ER_HYPERGRAPH_NOT_SUPPORTED_YET) {
1289 const char errstr[] = "<ignored hypergraph optimizer error: ";
1290 dynstr_append_mem(ds, errstr, sizeof(errstr) - 1);
1291 replace_dynstr_append(ds, err_error);
1292 dynstr_append_mem(ds, ">\n", 2);
1293 revert_properties();
1294 return;
1295 }
1296
1297
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 400500 times.
400537 if (command->abort_on_error) {
1298
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 34 times.
37 if (err_errno == ER_NO_SUCH_THREAD) {
1299 /* No such thread id, let's dump the available ones */
1300
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 fprintf(stderr,
1301 "mysqltest: query '%s returned ER_NO_SUCH_THREAD, "
1302 "dumping processlist\n",
1303 command->query);
1304
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 show_query(&cur_con->mysql, "SHOW PROCESSLIST");
1305 }
1306 37 die("Query '%s' failed.\nERROR %d (%s): %s", command->query, err_errno,
1307 err_sqlstate, err_error);
1308 }
1309
1310
3/8
✓ Branch 0 taken 400500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 400500 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 400500 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
400500 DBUG_PRINT("info", ("Expected errors count: %zu", expected_errors->count()));
1311
1312
1/2
✓ Branch 0 taken 400500 times.
✗ Branch 1 not taken.
400500 int i = match_expected_error(command, err_errno, err_sqlstate);
1313
1314
2/2
✓ Branch 0 taken 397534 times.
✓ Branch 1 taken 2966 times.
400500 if (i >= 0) {
1315
2/2
✓ Branch 0 taken 71637 times.
✓ Branch 1 taken 325897 times.
397534 if (!disable_result_log) {
1316
2/2
✓ Branch 0 taken 46907 times.
✓ Branch 1 taken 24730 times.
71637 if (expected_errors->count() == 1) {
1317 // Only log error if there is one possible error
1318
1/2
✓ Branch 0 taken 46907 times.
✗ Branch 1 not taken.
46907 dynstr_append_mem(ds, "ERROR ", 6);
1319
1/2
✓ Branch 0 taken 46907 times.
✗ Branch 1 not taken.
46907 replace_dynstr_append(ds, err_sqlstate);
1320
1/2
✓ Branch 0 taken 46907 times.
✗ Branch 1 not taken.
46907 dynstr_append_mem(ds, ": ", 2);
1321
1/2
✓ Branch 0 taken 46907 times.
✗ Branch 1 not taken.
46907 replace_dynstr_append(ds, err_error);
1322
1/2
✓ Branch 0 taken 46907 times.
✗ Branch 1 not taken.
46907 dynstr_append_mem(ds, "\n", 1);
1323 }
1324 // Don't log error if we may not get an error
1325
4/6
✓ Branch 0 taken 24730 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24730 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1897 times.
✓ Branch 5 taken 22833 times.
74190 else if (expected_errors->type() == ERR_SQLSTATE ||
1326
2/2
✓ Branch 0 taken 1897 times.
✓ Branch 1 taken 22833 times.
49460 (expected_errors->type() == ERR_ERRNO &&
1327 24730 expected_errors->error_code() != 0))
1328
1/2
✓ Branch 0 taken 1897 times.
✗ Branch 1 not taken.
1897 dynstr_append(ds, "Got one of the listed errors\n");
1329 }
1330
1331
1/2
✓ Branch 0 taken 397534 times.
✗ Branch 1 not taken.
397534 revert_properties();
1332 397534 return;
1333 }
1334
1335
3/8
✓ Branch 0 taken 2966 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2966 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2966 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2966 DBUG_PRINT("info",
1336 ("i: %d Expected errors count: %zu", i, expected_errors->count()));
1337
1338
2/2
✓ Branch 0 taken 2810 times.
✓ Branch 1 taken 156 times.
2966 if (!disable_result_log) {
1339
1/2
✓ Branch 0 taken 2810 times.
✗ Branch 1 not taken.
2810 dynstr_append_mem(ds, "ERROR ", 6);
1340
1/2
✓ Branch 0 taken 2810 times.
✗ Branch 1 not taken.
2810 replace_dynstr_append(ds, err_sqlstate);
1341
1/2
✓ Branch 0 taken 2810 times.
✗ Branch 1 not taken.
2810 dynstr_append_mem(ds, ": ", 2);
1342
1/2
✓ Branch 0 taken 2810 times.
✗ Branch 1 not taken.
2810 replace_dynstr_append(ds, err_error);
1343
1/2
✓ Branch 0 taken 2810 times.
✗ Branch 1 not taken.
2810 dynstr_append_mem(ds, "\n", 1);
1344 }
1345
1346
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2954 times.
2966 if (expected_errors->count()) {
1347
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 if (err_errno == ER_NO_SUCH_THREAD) {
1348 /* No such thread id, let's dump the available ones */
1349
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 fprintf(stderr,
1350 "mysqltest: query '%s returned ER_NO_SUCH_THREAD, "
1351 "dumping processlist\n",
1352 command->query);
1353
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 show_query(&cur_con->mysql, "SHOW PROCESSLIST");
1354 }
1355
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (expected_errors->count() == 1) {
1356 12 die("Query '%s' failed with wrong error %d: '%s', should have failed "
1357 "with error '%s'.",
1358 command->query, err_errno, err_error,
1359
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 expected_errors->error_list().c_str());
1360 } else {
1361 die("Query '%s' failed with wrong error %d: '%s', should have failed "
1362 "with any of '%s' errors.",
1363 command->query, err_errno, err_error,
1364 expected_errors->error_list().c_str());
1365 }
1366 }
1367
1368
1/2
✓ Branch 0 taken 2954 times.
✗ Branch 1 not taken.
2954 revert_properties();
1369
2/2
✓ Branch 0 taken 2954 times.
✓ Branch 1 taken 397534 times.
400488 }
1370
1371 /// Handle absence of errors after execution.
1372 ///
1373 /// Abort test run if the query succeeds and was expected to fail with
1374 /// an error.
1375 ///
1376 /// @param command Pointer to the st_command structure which holds the
1377 /// arguments and information for the command.
1378 3769565 void handle_no_error(struct st_command *command) {
1379
1/2
✓ Branch 0 taken 3769565 times.
✗ Branch 1 not taken.
3769565 DBUG_TRACE;
1380
1381
2/2
✓ Branch 0 taken 123479 times.
✓ Branch 1 taken 3646086 times.
3769565 if (expected_errors->count()) {
1382
1/2
✓ Branch 0 taken 123479 times.
✗ Branch 1 not taken.
123479 int index = match_expected_error(command, 0, "00000");
1383
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 123476 times.
123479 if (index == -1) {
1384
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (expected_errors->count() == 1) {
1385 3 die("Query '%s' succeeded, should have failed with error '%s'",
1386
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 command->query, expected_errors->error_list().c_str());
1387 } else {
1388 die("Query '%s' succeeded, should have failed with any of '%s' errors.",
1389 command->query, expected_errors->error_list().c_str());
1390 }
1391 }
1392 }
1393 3769562 }
1394
1395 /// Save error code returned by a mysqltest command in '$__error'
1396 /// variable.
1397 ///
1398 /// @param error Error code
1399 382539 static void save_error_code(std::uint32_t error) {
1400 char error_value[10];
1401 382539 size_t error_length = std::snprintf(error_value, 10, "%u", error);
1402 382539 error_value[error_length > 9 ? 9 : error_length] = '0';
1403 382539 const char *var_name = "__error";
1404
1/2
✓ Branch 0 taken 382539 times.
✗ Branch 1 not taken.
382539 var_set(var_name, var_name + 7, error_value, error_value + error_length);
1405 382539 }
1406
1407 /// Handle errors which occurred during execution of mysqltest commands
1408 /// like 'move_file', 'remove_file' etc which are used to perform file
1409 /// system operations.
1410 ///
1411 /// @param command Pointer to the st_command structure which holds the
1412 /// arguments and information for the command.
1413 /// @param error Error number
1414 ///
1415 /// @note
1416 /// If there is an unexpected error, this function will abort mysqltest
1417 /// client immediately.
1418 348436 static void handle_command_error(struct st_command *command,
1419 std::uint32_t error) {
1420
1/2
✓ Branch 0 taken 348436 times.
✗ Branch 1 not taken.
348436 DBUG_TRACE;
1421
3/8
✓ Branch 0 taken 348436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 348436 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 348436 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
348436 DBUG_PRINT("enter", ("error: %d", error));
1422
1423
4/4
✓ Branch 0 taken 37271 times.
✓ Branch 1 taken 311165 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 37262 times.
348436 if (error != 0 && command->abort_on_error) {
1424
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 die("Command \"%s\" failed with error %d. my_errno=%d.",
1425 9 command_names[command->type - 1], error, my_errno());
1426 }
1427
1428
2/2
✓ Branch 0 taken 37650 times.
✓ Branch 1 taken 310777 times.
348427 if (expected_errors->count()) {
1429
1/2
✓ Branch 0 taken 37647 times.
✗ Branch 1 not taken.
37650 int index = match_expected_error(command, error, nullptr);
1430
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 37645 times.
37647 if (index == -1) {
1431
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (error != 0) {
1432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (expected_errors->count() == 1) {
1433 die("Command \"%s\" failed with wrong error: %d, my_errno=%d. should "
1434 "have failed with error '%s'.",
1435 command_names[command->type - 1], error, my_errno(),
1436 expected_errors->error_list().c_str());
1437 } else {
1438
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 die("Command \"%s\" failed with wrong error: %d, my_errno=%d. should "
1439 "have failed with any of '%s' errors.",
1440 2 command_names[command->type - 1], error, my_errno(),
1441
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 expected_errors->error_list().c_str());
1442 }
1443 } else {
1444 // Command succeeded, should have failed with an error
1445 if (expected_errors->count() == 1) {
1446 die("Command \"%s\" succeeded, should have failed with error '%s'.",
1447 command_names[command->type - 1],
1448 expected_errors->error_list().c_str());
1449 } else {
1450 die("Command \"%s\" succeeded, should have failed with any of '%s' "
1451 "errors.",
1452 command_names[command->type - 1],
1453 expected_errors->error_list().c_str());
1454 }
1455 }
1456 }
1457 }
1458
1459 // Save the error code
1460
1/2
✓ Branch 0 taken 348422 times.
✗ Branch 1 not taken.
348422 save_error_code(error);
1461
1462
1/2
✓ Branch 0 taken 348422 times.
✗ Branch 1 not taken.
348422 revert_properties();
1463 348422 }
1464
1465 50111 static void close_connections() {
1466
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 DBUG_TRACE;
1467
2/2
✓ Branch 0 taken 92685 times.
✓ Branch 1 taken 50111 times.
142796 for (--next_con; next_con >= connections; --next_con) {
1468
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 92685 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
92685 if (next_con->stmt) mysql_stmt_close(next_con->stmt);
1469 92685 next_con->stmt = nullptr;
1470
1/2
✓ Branch 0 taken 92685 times.
✗ Branch 1 not taken.
92685 mysql_close(&next_con->mysql);
1471
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 92685 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
92685 if (next_con->util_mysql) mysql_close(next_con->util_mysql);
1472
1/2
✓ Branch 0 taken 92685 times.
✗ Branch 1 not taken.
92685 my_free(next_con->name);
1473 }
1474
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 my_free(connections);
1475 50111 }
1476
1477 11029 static void close_statements() {
1478 struct st_connection *con;
1479
1/2
✓ Branch 0 taken 11029 times.
✗ Branch 1 not taken.
11029 DBUG_TRACE;
1480
2/2
✓ Branch 0 taken 88920 times.
✓ Branch 1 taken 11029 times.
99949 for (con = connections; con < next_con; con++) {
1481
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 88920 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
88920 if (con->stmt) mysql_stmt_close(con->stmt);
1482 88920 con->stmt = nullptr;
1483 }
1484 11029 }
1485
1486 50126 static void close_files() {
1487
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 DBUG_TRACE;
1488
2/2
✓ Branch 0 taken 50560 times.
✓ Branch 1 taken 50126 times.
100686 for (; cur_file >= file_stack; cur_file--) {
1489
4/4
✓ Branch 0 taken 14779 times.
✓ Branch 1 taken 35781 times.
✓ Branch 2 taken 14068 times.
✓ Branch 3 taken 711 times.
50560 if (cur_file->file && cur_file->file != stdin) {
1490
3/8
✓ Branch 0 taken 14068 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14068 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14068 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14068 DBUG_PRINT("info", ("closing file: %s", cur_file->file_name));
1491
1/2
✓ Branch 0 taken 14068 times.
✗ Branch 1 not taken.
14068 fclose(cur_file->file);
1492 }
1493
1/2
✓ Branch 0 taken 50560 times.
✗ Branch 1 not taken.
50560 my_free(cur_file->file_name);
1494 50560 cur_file->file_name = nullptr;
1495 }
1496 50126 }
1497
1498 50126 static void free_used_memory() {
1499 // Delete the expected errors pointer
1500
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 delete expected_errors;
1501
1502 // Delete disabled and enabled warning list
1503
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 delete disabled_warnings;
1504
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 delete enabled_warnings;
1505
1506
2/2
✓ Branch 0 taken 50111 times.
✓ Branch 1 taken 15 times.
50126 if (connections) close_connections();
1507 50126 close_files();
1508
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 delete var_hash;
1509 50126 var_hash = nullptr;
1510
1511 struct st_command **q;
1512
2/2
✓ Branch 0 taken 409576039 times.
✓ Branch 1 taken 50126 times.
409626165 for (q = q_lines->begin(); q != q_lines->end(); ++q) {
1513 409576039 my_free((*q)->query_buf);
1514
2/2
✓ Branch 0 taken 463331 times.
✓ Branch 1 taken 409112708 times.
409576039 if ((*q)->content.str) dynstr_free(&(*q)->content);
1515 409576039 my_free((*q));
1516 }
1517
1518
2/2
✓ Branch 0 taken 501260 times.
✓ Branch 1 taken 50126 times.
551386 for (size_t i = 0; i < 10; i++) {
1519
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 501090 times.
501260 if (var_reg[i].alloced_len) my_free(var_reg[i].str_val);
1520 }
1521
1522
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 delete q_lines;
1523 50126 dynstr_free(&ds_res);
1524 50126 dynstr_free(&ds_result);
1525
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 50077 times.
50126 if (ds_warn) dynstr_free(ds_warn);
1526 50126 free_all_replace();
1527 50126 my_free(opt_pass);
1528 #ifdef _WIN32
1529 free_win_path_patterns();
1530 #endif
1531
1532
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 if (global_attrs != nullptr) {
1533
1/2
✓ Branch 0 taken 50126 times.
✗ Branch 1 not taken.
50126 delete global_attrs;
1534 50126 global_attrs = nullptr;
1535 }
1536
1537 // Only call mysql_server_end if mysql_server_init has been called.
1538
2/2
✓ Branch 0 taken 50111 times.
✓ Branch 1 taken 15 times.
50126 if (server_initialized) mysql_server_end();
1539
1540 // Don't use DBUG after mysql_server_end()
1541 50126 return;
1542 }
1543
1544 50126 static void cleanup_and_exit(int exit_code) {
1545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50126 times.
50126 if (opt_offload_count_file) {
1546 // Check if the current connection is active, if not create one.
1547 if (cur_con->mysql.net.vio == nullptr) {
1548 mysql_real_connect(&cur_con->mysql, opt_host, opt_user, opt_pass, opt_db,
1549 opt_port, unix_sock,
1550 CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS);
1551 }
1552
1553 // Save the final value of secondary engine execution status.
1554 if (secondary_engine->offload_count(&cur_con->mysql, "after"))
1555 exit_code = 1;
1556 secondary_engine->report_offload_count(opt_offload_count_file);
1557 }
1558
1559 50126 free_used_memory();
1560 50126 my_end(my_end_arg);
1561
1562 enum test_exit_code { PASS, FAIL, SKIPPED = 62, NOSKIP_PASS, NOSKIP_FAIL };
1563
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 50123 times.
50126 if (skip_ignored) {
1564
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 exit_code = (exit_code == PASS) ? NOSKIP_PASS : NOSKIP_FAIL;
1565 }
1566
1567
2/2
✓ Branch 0 taken 39657 times.
✓ Branch 1 taken 10469 times.
50126 if (!silent) {
1568
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 26439 times.
✓ Branch 2 taken 13217 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
39657 switch (exit_code) {
1569 1 case FAIL:
1570 1 printf("not ok\n");
1571 1 break;
1572 26439 case PASS:
1573 26439 printf("ok\n");
1574 26439 break;
1575 13217 case SKIPPED:
1576 13217 printf("skipped\n");
1577 13217 break;
1578 case NOSKIP_PASS:
1579 printf("noskip-passed\n");
1580 break;
1581 case NOSKIP_FAIL:
1582 printf("noskip-failed\n");
1583 break;
1584 default:
1585 printf("unknown exit code: %d\n", exit_code);
1586 assert(0);
1587 }
1588 }
1589
1590 // exit() appears to be not 100% reliable on Windows under some conditions.
1591 #ifdef _WIN32
1592 if (opt_safe_process_pid) {
1593 // Close the stack trace request event handle
1594 if (stacktrace_request_event != NULL) CloseHandle(stacktrace_request_event);
1595
1596 // Detach or stop the thread waiting for stack trace event to occur.
1597 if (wait_for_stacktrace_request_event_thread.joinable())
1598 wait_for_stacktrace_request_event_thread.detach();
1599
1600 // Close the thread handle
1601 if (!CloseHandle(mysqltest_thread))
1602 die("CloseHandle failed, err = %d.\n", GetLastError());
1603 }
1604
1605 fflush(stdout);
1606 fflush(stderr);
1607 _exit(exit_code);
1608 #else
1609 50126 exit(exit_code);
1610 #endif
1611 }
1612
1613 13578 static void print_file_stack() {
1614 13578 fprintf(stderr, "file %s: %d\n", cur_file->file_name, cur_file->lineno);
1615
1616 struct st_test_file *err_file;
1617
2/2
✓ Branch 0 taken 434 times.
✓ Branch 1 taken 13578 times.
14012 for (err_file = cur_file - 1; err_file >= file_stack; err_file--) {
1618 434 fprintf(stderr, "included from %s: %d\n", err_file->file_name,
1619 err_file->lineno);
1620 }
1621 13578 }
1622
1623 792 void die(const char *fmt, ...) {
1624 static int dying = 0;
1625 va_list args;
1626
3/8
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 792 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 792 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
792 DBUG_PRINT("enter", ("start_lineno: %d", start_lineno));
1627
1628 // Flush whatever was printed by the failing command before it died.
1629
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 flush_ds_res();
1630
1631 // Protect against dying twice first time 'die' is called, try to
1632 // write log files second time, just exit.
1633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 792 times.
792 if (dying) cleanup_and_exit(1);
1634 792 dying = 1;
1635
1636 // Print the error message
1637
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 fprintf(stderr, "mysqltest: ");
1638
1639
3/4
✓ Branch 0 taken 743 times.
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 743 times.
✗ Branch 3 not taken.
792 if (start_lineno > 0) fprintf(stderr, "At line %u: ", start_lineno);
1640
1641
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 if (fmt) {
1642 792 va_start(args, fmt);
1643
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 vfprintf(stderr, fmt, args);
1644
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 fprintf(stderr, "\n");
1645 792 va_end(args);
1646 } else
1647 fprintf(stderr, "Unknown error");
1648
1649 // Print the file stack
1650
3/4
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 750 times.
792 if (cur_file && cur_file != file_stack) {
1651
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 fprintf(stderr, "In included ");
1652
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 print_file_stack();
1653 }
1654
1655
1/2
✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
792 fflush(stderr);
1656
1657
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 739 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
792 if (result_file_name) log_file.show_tail(opt_tail_lines);
1658
1659 // Help debugging by displaying any warnings that might have
1660 // been produced prior to the error.
1661
5/6
✓ Branch 0 taken 769 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 732 times.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 732 times.
✗ Branch 5 not taken.
792 if (cur_con && !cur_con->pending) show_warnings_before_error(&cur_con->mysql);
1662
1663 792 cleanup_and_exit(1);
1664 }
1665
1666 13536 void abort_not_supported_test(const char *fmt, ...) {
1667 va_list args;
1668
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 DBUG_TRACE;
1669
1670 /* Print include filestack */
1671
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 fprintf(stderr, "The test '%s' is not supported by this installation\n",
1672 file_stack->file_name);
1673
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 fprintf(stderr, "Detected in ");
1674
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 print_file_stack();
1675
1676 /* Print error message */
1677 13536 va_start(args, fmt);
1678
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 if (fmt) {
1679
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 fprintf(stderr, "reason: ");
1680
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 vfprintf(stderr, fmt, args);
1681
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 fprintf(stderr, "\n");
1682
1/2
✓ Branch 0 taken 13536 times.
✗ Branch 1 not taken.
13536 fflush(stderr);
1683 }
1684 13536 va_end(args);
1685
1686 13536 cleanup_and_exit(62);
1687 }
1688
1689 322163 void verbose_msg(const char *fmt, ...) {
1690 va_list args;
1691
1/2
✓ Branch 0 taken 322163 times.
✗ Branch 1 not taken.
322163 DBUG_TRACE;
1692
2/2
✓ Branch 0 taken 137175 times.
✓ Branch 1 taken 184988 times.
322163 if (!verbose) return;
1693
1694 184988 va_start(args, fmt);
1695
1/2
✓ Branch 0 taken 184988 times.
✗ Branch 1 not taken.
184988 fprintf(stderr, "mysqltest: ");
1696
2/4
✓ Branch 0 taken 184988 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 184988 times.
184988 if (cur_file && cur_file != file_stack)
1697 fprintf(stderr, "In included file \"%s\": ", cur_file->file_name);
1698
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 184988 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
184988 if (start_lineno != 0) fprintf(stderr, "At line %u: ", start_lineno);
1699
1/2
✓ Branch 0 taken 184988 times.
✗ Branch 1 not taken.
184988 vfprintf(stderr, fmt, args);
1700
1/2
✓ Branch 0 taken 184988 times.
✗ Branch 1 not taken.
184988 fprintf(stderr, "\n");
1701 184988 va_end(args);
1702
2/2
✓ Branch 0 taken 184988 times.
✓ Branch 1 taken 137175 times.
322163 }
1703
1704 18 void log_msg(const char *fmt, ...) {
1705 va_list args;
1706 char buff[1024];
1707 size_t len;
1708
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 DBUG_TRACE;
1709
1710 18 va_start(args, fmt);
1711 18 len = vsnprintf(buff, sizeof(buff) - 1, fmt, args);
1712 18 va_end(args);
1713
1714
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 dynstr_append_mem(&ds_res, buff, len);
1715
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 dynstr_append(&ds_res, "\n");
1716 18 }
1717
1718 1824013593 void flush_ds_res() {
1719
2/2
✓ Branch 0 taken 3045878 times.
✓ Branch 1 taken 1820967715 times.
1824013593 if (ds_res.length) {
1720
3/6
✓ Branch 0 taken 3045878 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3045878 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3045878 times.
3045878 if (log_file.write(ds_res.str, ds_res.length) || log_file.flush())
1721 cleanup_and_exit(1);
1722
1723
2/2
✓ Branch 0 taken 26622 times.
✓ Branch 1 taken 3019256 times.
3045878 if (!result_file_name) {
1724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26622 times.
26622 if (std::fwrite(ds_res.str, 1, ds_res.length, stdout) != ds_res.length)
1725 cleanup_and_exit(1);
1726 26622 std::fflush(stdout);
1727 }
1728
1729 3045878 dynstr_set(&ds_res, nullptr);
1730 }
1731 1824013593 }
1732
1733 /*
1734 Read a file and append it to ds
1735
1736 SYNOPSIS
1737 cat_file
1738 ds - pointer to dynamic string where to add the files content
1739 filename - name of the file to read
1740
1741 */
1742
1743 13147 static int cat_file(DYNAMIC_STRING *ds, const char *filename) {
1744 int fd;
1745 size_t len;
1746 char buff[512];
1747 13147 bool dangling_cr = false;
1748
1749
3/4
✓ Branch 0 taken 13147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 13135 times.
13147 if ((fd = my_open(filename, O_RDONLY, MYF(0))) < 0) return 1;
1750
1751 13135 std::string file_content;
1752
1753
3/4
✓ Branch 0 taken 24099 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10964 times.
✓ Branch 3 taken 13135 times.
24099 while ((len = my_read(fd, (uchar *)&buff, sizeof(buff), MYF(0))) > 0) {
1754 10964 char *p = buff, *start = buff;
1755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10964 times.
10964 if (dangling_cr) {
1756 if (*p != '\n') file_content.append("\r");
1757 dangling_cr = false;
1758 }
1759
2/2
✓ Branch 0 taken 3788042 times.
✓ Branch 1 taken 10964 times.
3799006 while (p < buff + len) {
1760 /* Convert cr/lf to lf */
1761
4/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3788030 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
3788042 if (*p == '\r' && *(p + 1) && *(p + 1) == '\n') {
1762 /* Add fake newline instead of cr and output the line */
1763 12 *p = '\n';
1764 12 p++; /* Step past the "fake" newline */
1765
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 file_content.append(start, p - start);
1766 12 p++; /* Step past the "fake" newline */
1767 12 start = p;
1768 } else
1769 3788030 p++;
1770 }
1771
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10964 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10964 if (*(p - 1) == '\r' && len == 512) dangling_cr = true;
1772 size_t buf_len;
1773 /* Add any characters that might be left */
1774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10964 times.
10964 if (dangling_cr)
1775 buf_len = p - start - 1;
1776 else
1777 10964 buf_len = p - start;
1778
1/2
✓ Branch 0 taken 10964 times.
✗ Branch 1 not taken.
10964 file_content.append(start, buf_len);
1779 }
1780
1781
1/2
✓ Branch 0 taken 13135 times.
✗ Branch 1 not taken.
13135 replace_dynstr_append(ds, file_content.c_str());
1782
1/2
✓ Branch 0 taken 13135 times.
✗ Branch 1 not taken.
13135 my_close(fd, MYF(0));
1783
1784 13135 return 0;
1785 13135 }
1786
1787 /*
1788 Run the specified command with popen
1789
1790 SYNOPSIS
1791 run_command
1792 cmd - command to execute(should be properly quoted
1793 ds_res- pointer to dynamic string where to store the result
1794
1795 */
1796
1797 11 static int run_command(char *cmd, DYNAMIC_STRING *ds_res) {
1798 11 char buf[512] = {0};
1799 FILE *res_file;
1800 int error;
1801
1802
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (!(res_file = popen(cmd, "r"))) die("popen(\"%s\", \"r\") failed", cmd);
1803
1804
3/4
✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 11 times.
145 while (fgets(buf, sizeof(buf), res_file)) {
1805
3/8
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 134 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 134 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
134 DBUG_PRINT("info", ("buf: %s", buf));
1806
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 if (ds_res) {
1807 /* Save the output of this command in the supplied string */
1808
1/2
✓ Branch 0 taken 134 times.
✗ Branch 1 not taken.
134 dynstr_append(ds_res, buf);
1809 } else {
1810 /* Print it directly on screen */
1811 fprintf(stdout, "%s", buf);
1812 }
1813 }
1814
1815
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 error = pclose(res_file);
1816 11 return WEXITSTATUS(error);
1817 }
1818
1819 /*
1820 Run the specified tool with variable number of arguments
1821
1822 SYNOPSIS
1823 run_tool
1824 tool_path - the name of the tool to run
1825 ds_res - pointer to dynamic string where to store the result
1826 ... - variable number of arguments that will be properly
1827 quoted and appended after the tool's name
1828
1829 */
1830
1831 11 static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...) {
1832 int ret;
1833 const char *arg;
1834 va_list args;
1835 DYNAMIC_STRING ds_cmdline;
1836
1837
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 DBUG_TRACE;
1838
3/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
11 DBUG_PRINT("enter", ("tool_path: %s", tool_path));
1839
1840
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (init_dynamic_string(&ds_cmdline, IF_WIN("\"", ""), FN_REFLEN))
1841 die("Out of memory");
1842
1843
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 dynstr_append_os_quoted(&ds_cmdline, tool_path, NullS);
1844
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 dynstr_append(&ds_cmdline, " ");
1845
1846 11 va_start(args, ds_res);
1847
1848
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 11 times.
55 while ((arg = va_arg(args, char *))) {
1849 /* Options should be os quoted */
1850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (std::strncmp(arg, "--", 2) == 0)
1851 dynstr_append_os_quoted(&ds_cmdline, arg, NullS);
1852 else
1853
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 dynstr_append(&ds_cmdline, arg);
1854
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 dynstr_append(&ds_cmdline, " ");
1855 }
1856
1857 11 va_end(args);
1858
1859 #ifdef _WIN32
1860 dynstr_append(&ds_cmdline, "\"");
1861 #endif
1862
1863
3/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
11 DBUG_PRINT("info", ("Running: %s", ds_cmdline.str));
1864
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 ret = run_command(ds_cmdline.str, ds_res);
1865
3/8
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
11 DBUG_PRINT("exit", ("ret: %d", ret));
1866
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 dynstr_free(&ds_cmdline);
1867 11 return ret;
1868 11 }
1869
1870 /*
1871 Test if diff is present. This is needed on Windows systems
1872 as the OS returns 1 whether diff is successful or if it is
1873 not present.
1874
1875 We run diff -v and look for output in stdout.
1876 We don't redirect stderr to stdout to make for a simplified check
1877 Windows will output '"diff"' is not recognized... to stderr if it is
1878 not present.
1879 */
1880
1881 #ifdef _WIN32
1882
1883 static int diff_check(const char *diff_name) {
1884 FILE *res_file;
1885 char buf[128];
1886 int have_diff = 0;
1887
1888 snprintf(buf, sizeof(buf), "%s -v", diff_name);
1889
1890 if (!(res_file = popen(buf, "r"))) die("popen(\"%s\", \"r\") failed", buf);
1891
1892 /* if diff is not present, nothing will be in stdout to increment have_diff */
1893 if (fgets(buf, sizeof(buf), res_file)) have_diff = 1;
1894
1895 pclose(res_file);
1896
1897 return have_diff;
1898 }
1899
1900 #endif
1901
1902 /**
1903 See if the diff consists _solely_ of hunks that are due to output lines being
1904 replaced with the special hypergraph error text. If so, return true.
1905 An example hunk:
1906
1907 @@ -315,45 +211,25 @@
1908 SELECT * FROM articles WHERE MATCH(title, body) AGAINST('a' IN BOOLEAN MODE);
1909 -id title body
1910 -3 foo bar
1911 -2 bar baz
1912 +<ignored hypergraph optimizer error: The hypergraph optimizer does not yet
1913 support 'fulltext search'> SELECT ...
1914 */
1915 static bool is_diff_clean_except_hypergraph(DYNAMIC_STRING *ds) {
1916 constexpr char error_signature[] = "+<ignored hypergraph optimizer error: ";
1917
1918 enum STATE {
1919 LOOKING_FOR_FIRST_HUNK,
1920 IN_HUNK,
1921 FOUND_NEGATIVE_LINE
1922 } state = LOOKING_FOR_FIRST_HUNK;
1923
1924 const char *end = ds->str + ds->length;
1925 const char *line_end;
1926 for (const char *ptr = ds->str; ptr < end; ptr = line_end + 1) {
1927 line_end = pointer_cast<const char *>(memchr(ptr, '\n', end - ptr));
1928 if (line_end == nullptr) {
1929 line_end = end;
1930 }
1931
1932 size_t line_length = line_end - ptr;
1933 if (state == LOOKING_FOR_FIRST_HUNK) {
1934 if (line_length < 2) {
1935 // Malformed diff, give up.
1936 return false;
1937 }
1938 if (ptr[0] == '@' && ptr[1] == '@') {
1939 // Beginning of hunk.
1940 state = IN_HUNK;
1941 } else {
1942 // Still waiting for the first hunk.
1943 }
1944 } else {
1945 assert(state == IN_HUNK || state == FOUND_NEGATIVE_LINE);
1946
1947 if (line_length < 1) {
1948 // Malformed diff, give up.
1949 return false;
1950 }
1951 if (ptr[0] == '-') {
1952 // A group of negative diff lines (either the beginning, or more
1953 // of them). Hopefully, this group will be ended with an instance of
1954 // "+<ignored hypergraph optimizer ...", which means we can ignore it.
1955 state = FOUND_NEGATIVE_LINE;
1956 } else if (ptr[0] == ' ') {
1957 if (state == IN_HUNK) {
1958 // Waiting for the next (or first) diff. Continue.
1959 } else {
1960 // Negative lines that were not followed by an ignored error.
1961 // These are not acceptable.
1962 return false;
1963 }
1964 } else if (line_length >= 2 && ptr[0] == '@' && ptr[1] == '@') {
1965 // Beginning of a new hunk.
1966 if (state == FOUND_NEGATIVE_LINE) {
1967 // Negative lines that were not followed by an ignored error.
1968 // These are not acceptable.
1969 return false;
1970 }
1971 } else if (ptr[0] == '+') {
1972 if (line_length >= strlen(error_signature) &&
1973 memcmp(ptr, error_signature, strlen(error_signature)) == 0) {
1974 // An ignored error. Whether there were previous negative lines
1975 // or not, that's fine; we can end and ignore this group.
1976 state = IN_HUNK;
1977 } else {
1978 // A non-ignored error.
1979 return false;
1980 }
1981 } else {
1982 // Malformed diff, give up.
1983 return false;
1984 }
1985 }
1986 }
1987
1988 if (state == FOUND_NEGATIVE_LINE) {
1989 // Negative lines that were not followed by an ignored error.
1990 // These are not acceptable.
1991 return false;
1992 }
1993
1994 // Found nothing else, so success!
1995 return true;
1996 }
1997
1998 /// Show the diff of two files using the systems builtin diff
1999 /// command. If no such diff command exist, just dump the content
2000 /// of the two files and inform about how to get "diff"
2001 ///
2002 /// @param ds Pointer to dynamic string where to add the
2003 /// diff. If NULL, print the diff to stderr.
2004 /// @param filename1 Name of the first file
2005 /// @param filename2 Name of the second file
2006 /// @return true if the diff should be ignored
2007 11 static bool show_diff(DYNAMIC_STRING *ds, const char *filename1,
2008 const char *filename2) {
2009 DYNAMIC_STRING ds_diff;
2010
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (init_dynamic_string(&ds_diff, "", 256)) die("Out of memory");
2011
2012 11 const char *diff_name = nullptr;
2013
2014 // Determine if we have diff on Windows. If yes, then needs special
2015 // processing due to return values on that OS. This test is only done
2016 // on Windows since it's only needed there in order to correctly
2017 // detect non-availibility of 'diff', and the way it's implemented
2018 // does not work with default 'diff' on Solaris.
2019 #ifdef _WIN32
2020 if (diff_check("diff"))
2021 diff_name = "diff";
2022 else if (diff_check("mtrdiff"))
2023 diff_name = "mtrdiff";
2024 else
2025 diff_name = 0;
2026 #else
2027 // Otherwise always assume it's called diff
2028 11 diff_name = "diff";
2029 #endif
2030
2031
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (diff_name) {
2032 11 int exit_code = 0;
2033 // Use 'diff --color=always' to print the colored diff if it is enabled
2034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (opt_colored_diff) {
2035 // Most "diff" tools return '> 1' if error
2036 exit_code = run_tool(diff_name, &ds_diff, "-u --color='always'",
2037 filename1, filename2, "2>&1", NULL);
2038
2039 if (exit_code > 1)
2040 die("Option '--colored-diff' is not supported on this machine. "
2041 "To get colored diff output, install GNU diffutils version "
2042 "3.4 or higher.");
2043 } else {
2044 // Colored diff is disabled, clear the diff string and try unified
2045 // diff with "diff -u".
2046
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 dynstr_set(&ds_diff, "");
2047
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 exit_code = run_tool(diff_name, &ds_diff, "-u", filename1, filename2,
2048 "2>&1", NULL);
2049
2050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (exit_code > 1) {
2051 // Clear the diff string and fallback to context diff with "diff -c"
2052 dynstr_set(&ds_diff, "");
2053 exit_code = run_tool(diff_name, &ds_diff, "-c", filename1, filename2,
2054 "2>&1", NULL);
2055
2056 if (exit_code > 1) {
2057 // Clear the diff string and fallback to simple diff with "diff"
2058 dynstr_set(&ds_diff, "");
2059 exit_code =
2060 run_tool(diff_name, &ds_diff, filename1, filename2, "2>&1", NULL);
2061 if (exit_code > 1) diff_name = nullptr;
2062 }
2063
3/6
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
11 } else if (exit_code == 1 && opt_hypergraph &&
2064 is_diff_clean_except_hypergraph(&ds_diff)) {
2065 dynstr_free(&ds_diff);
2066 return true;
2067 }
2068 }
2069 }
2070
2071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!diff_name) {
2072 // Fallback to dump both files to result file and inform
2073 // about installing "diff".
2074 dynstr_append(&ds_diff, "\n");
2075 dynstr_append(
2076 &ds_diff,
2077 "\n"
2078 "The two files differ but it was not possible to execute 'diff' in\n"
2079 "order to show only the difference. Instead the whole content of the\n"
2080 "two files was shown for you to diff manually.\n\n"
2081 "To get a better report you should install 'diff' on your system, "
2082 "which you\n"
2083 "for example can get from "
2084 "http://www.gnu.org/software/diffutils/diffutils.html\n"
2085 #ifdef _WIN32
2086 "or http://gnuwin32.sourceforge.net/packages/diffutils.htm\n"
2087 #endif
2088 "\n");
2089
2090 dynstr_append(&ds_diff, " --- ");
2091 dynstr_append(&ds_diff, filename1);
2092 dynstr_append(&ds_diff, " >>>\n");
2093 cat_file(&ds_diff, filename1);
2094 dynstr_append(&ds_diff, "<<<\n --- ");
2095 dynstr_append(&ds_diff, filename1);
2096 dynstr_append(&ds_diff, " >>>\n");
2097 cat_file(&ds_diff, filename2);
2098 dynstr_append(&ds_diff, "<<<<\n");
2099 }
2100
2101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ds)
2102 // Add the diff to output
2103 dynstr_append_mem(ds, ds_diff.str, ds_diff.length);
2104 else
2105 // Print diff directly to stderr
2106
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 fprintf(stderr, "%s\n", ds_diff.str);
2107
2108
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 dynstr_free(&ds_diff);
2109 11 return false;
2110 }
2111
2112 enum compare_files_result_enum {
2113 RESULT_OK = 0,
2114 RESULT_CONTENT_MISMATCH = 1,
2115 RESULT_LENGTH_MISMATCH = 2
2116 };
2117
2118 /*
2119 Compare two files, given a fd to the first file and
2120 name of the second file
2121
2122 SYNOPSIS
2123 compare_files2
2124 fd - Open file descriptor of the first file
2125 filename2 - Name of second file
2126
2127 RETURN VALUES
2128 According to the values in "compare_files_result_enum"
2129
2130 */
2131
2132 31185 static int compare_files2(File fd, const char *filename2) {
2133 31185 int error = RESULT_OK;
2134 File fd2;
2135 size_t len, len2;
2136 char buff[512], buff2[512];
2137
2138
2/4
✓ Branch 0 taken 31185 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31185 times.
31185 if ((fd2 = my_open(filename2, O_RDONLY, MYF(0))) < 0) {
2139 my_close(fd, MYF(0));
2140 die("Failed to open second file: '%s'", filename2);
2141 }
2142
3/4
✓ Branch 0 taken 3920464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3889302 times.
✓ Branch 3 taken 31162 times.
3920464 while ((len = my_read(fd, (uchar *)&buff, sizeof(buff), MYF(0))) > 0) {
2143
3/4
✓ Branch 0 taken 3889302 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 3889295 times.
3889302 if ((len2 = my_read(fd2, (uchar *)&buff2, sizeof(buff2), MYF(0))) < len) {
2144 /* File 2 was smaller */
2145 7 error = RESULT_LENGTH_MISMATCH;
2146 7 break;
2147 }
2148
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3889292 times.
3889295 if (len2 > len) {
2149 /* File 1 was smaller */
2150 3 error = RESULT_LENGTH_MISMATCH;
2151 3 break;
2152 }
2153
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3889279 times.
3889292 if ((memcmp(buff, buff2, len))) {
2154 /* Content of this part differed */
2155 13 error = RESULT_CONTENT_MISMATCH;
2156 13 break;
2157 }
2158 }
2159
5/8
✓ Branch 0 taken 31162 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 31162 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31162 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 31185 times.
31185 if (!error && my_read(fd2, (uchar *)&buff2, sizeof(buff2), MYF(0)) > 0) {
2160 /* File 1 was smaller */
2161 error = RESULT_LENGTH_MISMATCH;
2162 }
2163
2164
1/2
✓ Branch 0 taken 31185 times.
✗ Branch 1 not taken.
31185 my_close(fd2, MYF(0));
2165
2166 31185 return error;
2167 }
2168
2169 /*
2170 Compare two files, given their filenames
2171
2172 SYNOPSIS
2173 compare_files
2174 filename1 - Name of first file
2175 filename2 - Name of second file
2176
2177 RETURN VALUES
2178 See 'compare_files2'
2179
2180 */
2181
2182 31185 static int compare_files(const char *filename1, const char *filename2) {
2183 File fd;
2184 int error;
2185
2186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31185 times.
31185 if ((fd = my_open(filename1, O_RDONLY, MYF(0))) < 0)
2187 die("Failed to open first file: '%s'", filename1);
2188
2189 31185 error = compare_files2(fd, filename2);
2190
2191 31185 my_close(fd, MYF(0));
2192
2193 31185 return error;
2194 }
2195
2196 /*
2197 Check the content of log against result file
2198
2199 SYNOPSIS
2200 check_result
2201
2202 RETURN VALUES
2203 error - the function will not return
2204
2205 */
2206
2207 22007 static void check_result() {
2208 22007 const char *mess = "Result content mismatch\n";
2209
2210
1/2
✓ Branch 0 taken 22007 times.
✗ Branch 1 not taken.
22007 DBUG_TRACE;
2211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22007 times.
22007 assert(result_file_name);
2212
3/8
✓ Branch 0 taken 22007 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22007 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 22007 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
22007 DBUG_PRINT("enter", ("result_file_name: %s", result_file_name));
2213
2214 /*
2215 Removing the unnecessary warning messages generated
2216 on GCOV platform.
2217 */
2218 #ifdef HAVE_GCOV
2219 char cmd[FN_REFLEN];
2220 22007 strcpy(cmd, "sed -i '/gcda:Merge mismatch for function/d' ");
2221 22007 std::strcat(cmd, log_file.file_name());
2222
1/2
✓ Branch 0 taken 22007 times.
✗ Branch 1 not taken.
22007 system(cmd);
2223 #endif
2224
2225
4/6
✓ Branch 0 taken 22007 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21996 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
22007 switch (compare_files(log_file.file_name(), result_file_name)) {
2226 21996 case RESULT_OK:
2227 21996 break; /* ok */
2228 4 case RESULT_LENGTH_MISMATCH:
2229 4 mess = "Result length mismatch\n";
2230 [[fallthrough]];
2231 11 case RESULT_CONTENT_MISMATCH: {
2232 /*
2233 Result mismatched, dump results to .reject file
2234 and then show the diff
2235 */
2236 char reject_file[FN_REFLEN];
2237 size_t reject_length;
2238
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 dirname_part(reject_file, result_file_name, &reject_length);
2239
2240 /* Put reject file in opt_logdir */
2241
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 fn_format(reject_file, result_file_name, opt_logdir, ".reject",
2242 MY_REPLACE_DIR | MY_REPLACE_EXT);
2243
2244
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (my_copy(log_file.file_name(), reject_file, MYF(0)) != 0)
2245 die("Failed to copy '%s' to '%s', errno: %d", log_file.file_name(),
2246 reject_file, errno);
2247
2248
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 bool ignored_diff = show_diff(nullptr, result_file_name, reject_file);
2249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (ignored_diff) {
2250 abort_not_supported_test(
2251 "Hypergraph optimizer did not support all queries.");
2252 }
2253 11 die("%s", mess);
2254 break;
2255 }
2256 default: /* impossible */
2257 die("Unknown error code from dyn_string_cmp()");
2258 }
2259 21996 }
2260
2261 /*
2262 Remove surrounding chars from string
2263
2264 Return 1 if first character is found but not last
2265 */
2266 716738 static int strip_surrounding(char *str, char c1, char c2) {
2267 716738 char *ptr = str;
2268
2269 /* Check if the first non space character is c1 */
2270
4/4
✓ Branch 0 taken 736212 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 19480 times.
✓ Branch 3 taken 716732 times.
736218 while (*ptr && my_isspace(charset_info, *ptr)) ptr++;
2271
2/2
✓ Branch 0 taken 361730 times.
✓ Branch 1 taken 355008 times.
716738 if (*ptr == c1) {
2272 /* Replace it with a space */
2273 361730 *ptr = ' ';
2274
2275 /* Last non space character should be c2 */
2276 361730 ptr = strend(str) - 1;
2277
3/4
✓ Branch 0 taken 361744 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 361730 times.
361744 while (*ptr && my_isspace(charset_info, *ptr)) ptr--;
2278
2/2
✓ Branch 0 taken 361727 times.
✓ Branch 1 taken 3 times.
361730 if (*ptr == c2) {
2279 /* Replace it with \0 */
2280 361727 *ptr = 0;
2281 } else {
2282 /* Mismatch detected */
2283 3 return 1;
2284 }
2285 }
2286 716735 return 0;
2287 }
2288
2289 381510 static void strip_parentheses(struct st_command *command) {
2290
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 381507 times.
381510 if (strip_surrounding(command->first_argument, '(', ')'))
2291 3 die("%.*s - argument list started with '%c' must be ended with '%c'",
2292 3 static_cast<int>(command->first_word_len), command->query, '(', ')');
2293 381507 }
2294
2295 2844247 void var_free::operator()(VAR *var) const {
2296 2844247 my_free(var->str_val);
2297
1/2
✓ Branch 0 taken 2844247 times.
✗ Branch 1 not taken.
2844247 if (var->alloced) my_free(var);
2298 2844247 }
2299
2300 63144937 static void var_check_int(VAR *v) {
2301 char *endptr;
2302 63144937 char *str = v->str_val;
2303
2304 /* Initially assume not a number */
2305 63144937 v->int_val = 0;
2306 63144937 v->is_int = false;
2307 63144937 v->int_dirty = false;
2308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63144937 times.
63144937 if (!str) return;
2309
2310 63144937 v->int_val = (int)strtol(str, &endptr, 10);
2311 /* It is an int if strtol consumed something up to end/space/tab */
2312
8/8
✓ Branch 0 taken 19347169 times.
✓ Branch 1 taken 43797768 times.
✓ Branch 2 taken 399731 times.
✓ Branch 3 taken 18947438 times.
✓ Branch 4 taken 268157 times.
✓ Branch 5 taken 131574 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 268143 times.
63144937 if (endptr > str && (!*endptr || *endptr == ' ' || *endptr == '\t'))
2313 19079026 v->is_int = true;
2314 }
2315
2316 25971795 VAR *var_init(VAR *v, const char *name, size_t name_len, const char *val,
2317 size_t val_len) {
2318 size_t val_alloc_len;
2319 VAR *tmp_var;
2320
3/4
✓ Branch 0 taken 23127503 times.
✓ Branch 1 taken 2844292 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23127503 times.
25971795 if (!name_len && name) name_len = std::strlen(name);
2321
4/4
✓ Branch 0 taken 25776424 times.
✓ Branch 1 taken 195371 times.
✓ Branch 2 taken 2648921 times.
✓ Branch 3 taken 23127503 times.
25971795 if (!val_len && val) val_len = std::strlen(val);
2322
2/2
✓ Branch 0 taken 23127503 times.
✓ Branch 1 taken 2844292 times.
25971795 if (!val) val_len = 0;
2323 25971795 val_alloc_len = val_len + 16; /* room to grow */
2324
4/6
✓ Branch 0 taken 2844292 times.
✓ Branch 1 taken 23127503 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2844292 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25971795 times.
25971795 if (!(tmp_var = v) && !(tmp_var = (VAR *)my_malloc(
2325 PSI_NOT_INSTRUMENTED,
2326 sizeof(*tmp_var) + name_len + 2, MYF(MY_WME))))
2327 die("Out of memory");
2328
2329
2/2
✓ Branch 0 taken 2844292 times.
✓ Branch 1 taken 23127503 times.
25971795 if (name != nullptr) {
2330 2844292 tmp_var->name = reinterpret_cast<char *>(tmp_var) + sizeof(*tmp_var);
2331 2844292 memcpy(tmp_var->name, name, name_len);
2332 2844292 tmp_var->name[name_len] = 0;
2333 } else
2334 23127503 tmp_var->name = nullptr;
2335
2336 25971795 tmp_var->alloced = (v == nullptr);
2337
2338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25971795 times.
25971795 if (!(tmp_var->str_val = (char *)my_malloc(PSI_NOT_INSTRUMENTED,
2339 val_alloc_len + 1, MYF(MY_WME))))
2340 die("Out of memory");
2341
2342
2/2
✓ Branch 0 taken 2844292 times.
✓ Branch 1 taken 23127503 times.
25971795 if (val) memcpy(tmp_var->str_val, val, val_len);
2343 25971795 tmp_var->str_val[val_len] = 0;
2344
2345 25971795 var_check_int(tmp_var);
2346 25971795 tmp_var->name_len = name_len;
2347 25971795 tmp_var->str_val_len = val_len;
2348 25971795 tmp_var->alloced_len = val_alloc_len;
2349 25971795 return tmp_var;
2350 }
2351
2352 752118 VAR *var_from_env(const char *name, const char *def_val) {
2353 const char *tmp;
2354 VAR *v;
2355
2/2
✓ Branch 0 taken 556733 times.
✓ Branch 1 taken 195385 times.
752118 if (!(tmp = getenv(name))) tmp = def_val;
2356
2357 752118 v = var_init(nullptr, name, std::strlen(name), tmp, std::strlen(tmp));
2358
1/2
✓ Branch 0 taken 752118 times.
✗ Branch 1 not taken.
752118 var_hash->emplace(name, std::unique_ptr<VAR, var_free>(v));
2359 752118 return v;
2360 }
2361
2362 47177088 VAR *var_get(const char *var_name, const char **var_name_end, bool raw,
2363 bool ignore_not_existing) {
2364 int digit;
2365 VAR *v;
2366
1/2
✓ Branch 0 taken 47177088 times.
✗ Branch 1 not taken.
47177088 DBUG_TRACE;
2367
3/8
✓ Branch 0 taken 47177088 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47177088 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 47177088 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
47177088 DBUG_PRINT("enter", ("var_name: %s", var_name));
2368
2369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47177088 times.
47177088 if (*var_name != '$') goto err;
2370 47177088 digit = *++var_name - '0';
2371
3/4
✓ Branch 0 taken 47177088 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45120920 times.
✓ Branch 3 taken 2056168 times.
47177088 if (digit < 0 || digit >= 10) {
2372 45120920 const char *save_var_name = var_name, *end;
2373 uint length;
2374
2/2
✓ Branch 0 taken 45119975 times.
✓ Branch 1 taken 945 times.
45120920 end = (var_name_end) ? *var_name_end : nullptr;
2375
5/6
✓ Branch 0 taken 142447735 times.
✓ Branch 1 taken 642988079 times.
✓ Branch 2 taken 97326815 times.
✓ Branch 3 taken 45120920 times.
✓ Branch 4 taken 740314894 times.
✗ Branch 5 not taken.
785435814 while (my_isvar(charset_info, *var_name) && var_name != end) var_name++;
2376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45120920 times.
45120920 if (var_name == save_var_name) {
2377 if (ignore_not_existing) return nullptr;
2378 die("Empty variable");
2379 }
2380 45120920 length = (uint)(var_name - save_var_name);
2381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45120920 times.
45120920 if (length >= MAX_VAR_NAME_LENGTH)
2382 die("Too long variable name: %s", save_var_name);
2383
2384
4/6
✓ Branch 0 taken 45120920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45120920 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 752118 times.
✓ Branch 5 taken 44368802 times.
45120920 if (!(v = find_or_nullptr(*var_hash, std::string(save_var_name, length)))) {
2385 char buff[MAX_VAR_NAME_LENGTH + 1];
2386
1/2
✓ Branch 0 taken 752118 times.
✗ Branch 1 not taken.
752118 strmake(buff, save_var_name, length);
2387
1/2
✓ Branch 0 taken 752118 times.
✗ Branch 1 not taken.
752118 v = var_from_env(buff, "");
2388 }
2389 45120920 var_name--; /* Point at last character */
2390 45120920 } else
2391 2056168 v = var_reg + digit;
2392
2393
4/4
✓ Branch 0 taken 43572251 times.
✓ Branch 1 taken 3604837 times.
✓ Branch 2 taken 3437322 times.
✓ Branch 3 taken 40134929 times.
47177088 if (!raw && v->int_dirty) {
2394 3437322 sprintf(v->str_val, "%d", v->int_val);
2395 3437322 v->int_dirty = false;
2396 3437322 v->str_val_len = std::strlen(v->str_val);
2397 }
2398
2/2
✓ Branch 0 taken 47176143 times.
✓ Branch 1 taken 945 times.
47177088 if (var_name_end) *var_name_end = var_name;
2399 47177088 return v;
2400 err:
2401 if (var_name_end) *var_name_end = nullptr;
2402 die("Unsupported variable name: %s", var_name);
2403 return nullptr;
2404 47177088 }
2405
2406 34330848 static VAR *var_obtain(const char *name, int len) {
2407
2/4
✓ Branch 0 taken 34330848 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34330848 times.
✗ Branch 3 not taken.
34330848 VAR *v = find_or_nullptr(*var_hash, std::string(name, len));
2408
2/2
✓ Branch 0 taken 2092174 times.
✓ Branch 1 taken 32238674 times.
34330848 if (v == nullptr) {
2409 2092174 v = var_init(nullptr, name, len, "", 0);
2410
2/4
✓ Branch 0 taken 2092174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2092174 times.
✗ Branch 3 not taken.
2092174 var_hash->emplace(std::string(name, len),
2411 4184348 std::unique_ptr<VAR, var_free>(v));
2412 }
2413 34330848 return v;
2414 }
2415
2416 /*
2417 - if variable starts with a $ it is regarded as a local test variable
2418 - if not it is treated as a environment variable, and the corresponding
2419 environment variable will be updated
2420 */
2421
2422 34335389 void var_set(const char *var_name, const char *var_name_end,
2423 const char *var_val, const char *var_val_end) {
2424 34335389 int digit, env_var = 0;
2425 VAR *v;
2426
1/2
✓ Branch 0 taken 34335389 times.
✗ Branch 1 not taken.
34335389 DBUG_TRACE;
2427
3/8
✓ Branch 0 taken 34335389 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34335389 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34335389 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
34335389 DBUG_PRINT("enter", ("var_name: '%.*s' = '%.*s' (length: %d)",
2428 (int)(var_name_end - var_name), var_name,
2429 (int)(var_val_end - var_val), var_val,
2430 (int)(var_val_end - var_val)));
2431
2432
2/2
✓ Branch 0 taken 1094945 times.
✓ Branch 1 taken 33240444 times.
34335389 if (*var_name != '$')
2433 1094945 env_var = 1;
2434 else
2435 33240444 var_name++;
2436
2437 34335389 digit = *var_name - '0';
2438
4/4
✓ Branch 0 taken 4543 times.
✓ Branch 1 taken 34330846 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 4541 times.
34335389 if (!(digit < 10 && digit >= 0)) {
2439
1/2
✓ Branch 0 taken 34330848 times.
✗ Branch 1 not taken.
34330848 v = var_obtain(var_name, (uint)(var_name_end - var_name));
2440 } else
2441 4541 v = var_reg + digit;
2442
2443
1/2
✓ Branch 0 taken 34335334 times.
✗ Branch 1 not taken.
34335389 eval_expr(v, var_val, (const char **)&var_val_end);
2444
2445
2/2
✓ Branch 0 taken 1094945 times.
✓ Branch 1 taken 33240389 times.
34335334 if (env_var) {
2446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1094945 times.
1094945 if (v->int_dirty) {
2447 sprintf(v->str_val, "%d", v->int_val);
2448 v->int_dirty = false;
2449 v->str_val_len = std::strlen(v->str_val);
2450 }
2451 /* setenv() expects \0-terminated strings */
2452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1094945 times.
1094945 assert(v->name[v->name_len] == 0);
2453 1094945 setenv(v->name, v->str_val, 1);
2454 }
2455 34335334 }
2456
2457 14144757 static void var_set_string(const char *name, const char *value) {
2458 14144757 var_set(name, name + std::strlen(name), value, value + std::strlen(value));
2459 14144757 }
2460
2461 8341485 static void var_set_int(const char *name, int value) {
2462 char buf[21];
2463 8341485 snprintf(buf, sizeof(buf), "%d", value);
2464
1/2
✓ Branch 0 taken 8341485 times.
✗ Branch 1 not taken.
8341485 var_set_string(name, buf);
2465 8341485 }
2466
2467 /*
2468 Store an integer (typically the returncode of the last SQL)
2469 statement in the mysqltest builtin variable $mysql_errno
2470 */
2471
2472 4213084 static void var_set_errno(int sql_errno) {
2473 4213084 var_set_int("$mysql_errno", sql_errno);
2474 4213084 var_set_string("$mysql_errname", get_errname_from_code(sql_errno));
2475 4213084 }
2476
2477 /// Variable '$DISABLED_WARNINGS_LIST' contains comma separated list
2478 /// of disabled warnings and variable '$ENABLED_WARNINGS_LIST' contains
2479 /// comma separated list of enabled warnings.
2480 ///
2481 /// Update the value of these two variables with the latest list of
2482 /// disabled and enabled warnings. The value of these variables will be
2483 /// empty if there are no disabled or enabled warnings.
2484 ///
2485 /// These variables will always contain the latest list of disabled
2486 /// and enabled warnings, and can be referenced inside a test or inside
2487 /// a test utility file to access the current list of disabled or
2488 /// enabled warnings.
2489 80208 static void update_disabled_enabled_warnings_list_var() {
2490 // Update '$DISABLED_WARNINGS_LIST' variable
2491
1/2
✓ Branch 0 taken 80208 times.
✗ Branch 1 not taken.
80208 std::string disabled_warning_list = disabled_warnings->warnings_list();
2492
1/2
✓ Branch 0 taken 80208 times.
✗ Branch 1 not taken.
80208 var_set_string("DISABLED_WARNINGS_LIST", disabled_warning_list.c_str());
2493
2494 // Update '$ENABLED_WARNINGS_LIST' variable
2495
1/2
✓ Branch 0 taken 80208 times.
✗ Branch 1 not taken.
80208 std::string enabled_warning_list = enabled_warnings->warnings_list();
2496
1/2
✓ Branch 0 taken 80208 times.
✗ Branch 1 not taken.
80208 var_set_string("ENABLED_WARNINGS_LIST", enabled_warning_list.c_str());
2497 80208 }
2498
2499 /// Set a property value to either 0 or 1 for a disable_X or a enable_X
2500 /// command, and the new value set will be applicable for next statement
2501 /// only. After that, property value will be reset back to the old value.
2502 ///
2503 /// @param property Enum value representing a Property
2504 /// @param value Value for the property, either 0 or 1
2505 15328 static void set_once_property(enum_prop property, bool value) {
2506 15328 Property &prop = prop_list[property];
2507 15328 prop.set = true;
2508 15328 prop.old = *prop.var;
2509 15328 *prop.var = value;
2510 15328 var_set_int(prop.env_name, (value != prop.reverse));
2511 15328 once_property = true;
2512 15328 }
2513
2514 /// Set a property value to either 0 or 1 for a disable_X or a enable_X
2515 /// command.
2516 ///
2517 /// @param command Pointer to the st_command structure which holds the
2518 /// arguments and information for the command.
2519 /// @param property Enum value representing a Property
2520 /// @param value Value for the property, either 0 or 1
2521 2232401 static void set_property(st_command *command, enum_prop property, bool value) {
2522 2232401 char *arg = command->first_argument;
2523
2524 // If "ONCE" argument is specified, the new value for the property is
2525 // set for next statement only. After that, property value will be
2526 // reset back to the old value.
2527
1/2
✓ Branch 0 taken 2232401 times.
✗ Branch 1 not taken.
2232401 if (arg) {
2528 // "ONCE" is the second argument to 'disable_warnings/enable_warnings'
2529 // command.
2530
2/2
✓ Branch 0 taken 2193096 times.
✓ Branch 1 taken 39305 times.
2232401 if (((command->type == Q_DISABLE_WARNINGS ||
2531
2/2
✓ Branch 0 taken 31476 times.
✓ Branch 1 taken 2161620 times.
2193096 command->type == Q_ENABLE_WARNINGS) &&
2532
2/2
✓ Branch 0 taken 69551 times.
✓ Branch 1 taken 1230 times.
70781 std::strstr(arg, "ONCE") != nullptr) ||
2533
2/2
✓ Branch 0 taken 14077 times.
✓ Branch 1 taken 2217094 times.
2231171 !std::strcmp(arg, "ONCE")) {
2534 15307 command->last_argument = arg + std::strlen(arg);
2535 15307 set_once_property(property, value);
2536 15307 return;
2537 }
2538 }
2539
2540 2217094 Property &prop = prop_list[property];
2541 2217094 prop.set = false;
2542 2217094 *prop.var = value;
2543 2217094 var_set_int(prop.env_name, (value != prop.reverse));
2544 }
2545
2546 /// Reset property value to the old value for all properties which are
2547 /// set for the next statement only, i.e properties specified using
2548 /// keyword "ONCE" argument.
2549 24258485 void revert_properties() {
2550
2/2
✓ Branch 0 taken 24249115 times.
✓ Branch 1 taken 9370 times.
24258485 if (!once_property) return;
2551
2552
2/2
✓ Branch 0 taken 93700 times.
✓ Branch 1 taken 9370 times.
103070 for (std::size_t i = 0; i < P_MAX; i++) {
2553 93700 Property &prop = prop_list[i];
2554
2/2
✓ Branch 0 taken 15328 times.
✓ Branch 1 taken 78372 times.
93700 if (prop.set) {
2555 15328 *prop.var = prop.old;
2556 15328 prop.set = false;
2557 15328 var_set_int(prop.env_name, (prop.old != prop.reverse));
2558 }
2559 }
2560
2561 // Remove warnings which are disabled or enabled for the next
2562 // statement only.
2563 9370 disabled_warnings->update_list();
2564 9370 enabled_warnings->update_list();
2565
2566 // Update $DISABLED_WARNINGS_LIST and $ENABLED_WARNINGS_LIST
2567 // variable value.
2568 9370 update_disabled_enabled_warnings_list_var();
2569
2570 9370 once_property = false;
2571 }
2572
2573 /*
2574 Set variable from the result of a query
2575
2576 SYNOPSIS
2577 var_query_set()
2578 var variable to set from query
2579 query start of query string to execute
2580 query_end end of the query string to execute
2581
2582
2583 DESCRIPTION
2584 let @<var_name> = `<query>`
2585
2586 Execute the query and assign the first row of result to var as
2587 a tab separated strings
2588
2589 Also assign each column of the result set to
2590 variable "$<var_name>_<column_name>"
2591 Thus the tab separated output can be read from $<var_name> and
2592 and each individual column can be read as $<var_name>_<col_name>
2593
2594 */
2595
2596 7256029 static void var_query_set(VAR *var, const char *query, const char **query_end) {
2597 7256029 const char *end =
2598
2/4
✓ Branch 0 taken 7256029 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7256029 times.
✗ Branch 3 not taken.
7256029 (query_end && *query_end) ? *query_end : query + std::strlen(query);
2599 7256029 MYSQL_RES *res = nullptr;
2600 MYSQL_ROW row;
2601 7256029 MYSQL *mysql = &cur_con->mysql;
2602 DYNAMIC_STRING ds_query;
2603
1/2
✓ Branch 0 taken 7256029 times.
✗ Branch 1 not taken.
7256029 DBUG_TRACE;
2604
2605 /* Only white space or ) allowed past ending ` */
2606
3/4
✓ Branch 0 taken 14521973 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7265953 times.
✓ Branch 3 taken 7256020 times.
14521973 while (end > query && *end != '`') {
2607
8/10
✓ Branch 0 taken 238523 times.
✓ Branch 1 taken 7027430 times.
✓ Branch 2 taken 228608 times.
✓ Branch 3 taken 9915 times.
✓ Branch 4 taken 228608 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 228608 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 228599 times.
7265953 if (*end && (*end != ' ' && *end != '\t' && *end != '\n' && *end != ')'))
2608 9 die("Spurious text after `query` expression");
2609 7265944 --end;
2610 }
2611
2612
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7256020 times.
7256020 if (query == end) die("Syntax error in query, missing '`'");
2613 7256020 ++query;
2614
2615 /* Eval the query, thus replacing all environment variables */
2616
1/2
✓ Branch 0 taken 7256020 times.
✗ Branch 1 not taken.
7256020 init_dynamic_string(&ds_query, nullptr, (end - query) + 32);
2617
1/2
✓ Branch 0 taken 7256020 times.
✗ Branch 1 not taken.
7256020 do_eval(&ds_query, query, end, false);
2618
2619 #ifdef WITH_WSREP
2620 /* Code altered (git-hash#3c205385752f)
2621 if a --let = `SELECT ...` query is interrupted, the test does not
2622 fail but the error is communicated to caller */
2623 21768060 if (mysql_real_query_wrapper(mysql, ds_query.str,
2624
5/6
✓ Branch 0 taken 7256020 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7249060 times.
✓ Branch 3 taken 6960 times.
✓ Branch 4 taken 6960 times.
✓ Branch 5 taken 7249060 times.
14505080 static_cast<ulong>(ds_query.length)) ||
2625
2/4
✓ Branch 0 taken 7249060 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7249060 times.
7249060 !(res = mysql_store_result_wrapper(mysql))) {
2626 #else
2627 if (mysql_real_query_wrapper(mysql, ds_query.str,
2628 static_cast<ulong>(ds_query.length))) {
2629 #endif /* WITH_WSREP */
2630
4/8
✓ Branch 0 taken 6960 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6960 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6960 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6957 times.
✗ Branch 7 not taken.
6960 handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
2631 mysql_sqlstate(mysql), &ds_res);
2632 /* If error was acceptable, return empty string */
2633
1/2
✓ Branch 0 taken 6957 times.
✗ Branch 1 not taken.
6957 dynstr_free(&ds_query);
2634
1/2
✓ Branch 0 taken 6957 times.
✗ Branch 1 not taken.
6957 eval_expr(var, "", nullptr);
2635 6957 return;
2636 }
2637
2638 #ifdef WITH_WSREP
2639 /* Do nothing */
2640 #else
2641 if (!(res = mysql_store_result_wrapper(mysql)))
2642 die("Query '%s' didn't return a result set", ds_query.str);
2643 #endif /* WITH_WSREP */
2644
1/2
✓ Branch 0 taken 7249060 times.
✗ Branch 1 not taken.
7249060 dynstr_free(&ds_query);
2645
2646
7/8
✓ Branch 0 taken 7249060 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7216962 times.
✓ Branch 3 taken 32098 times.
✓ Branch 4 taken 7216495 times.
✓ Branch 5 taken 467 times.
✓ Branch 6 taken 7216495 times.
✓ Branch 7 taken 32565 times.
7249060 if ((row = mysql_fetch_row_wrapper(res)) && row[0]) {
2647 /*
2648 Concatenate all fields in the first row with tab in between
2649 and assign that string to the $variable
2650 */
2651 DYNAMIC_STRING result;
2652 uint i;
2653 ulong *lengths;
2654
2655
1/2
✓ Branch 0 taken 7216495 times.
✗ Branch 1 not taken.
7216495 init_dynamic_string(&result, "", 512);
2656
1/2
✓ Branch 0 taken 7216495 times.
✗ Branch 1 not taken.
7216495 lengths = mysql_fetch_lengths(res);
2657
3/4
✓ Branch 0 taken 14436069 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7219574 times.
✓ Branch 3 taken 7216495 times.
14436069 for (i = 0; i < mysql_num_fields(res); i++) {
2658
1/2
✓ Branch 0 taken 7219574 times.
✗ Branch 1 not taken.
7219574 if (row[i]) {
2659 /* Add column to tab separated string */
2660 7219574 char *val = row[i];
2661 7219574 size_t len = lengths[i];
2662
2663
2/2
✓ Branch 0 taken 1721 times.
✓ Branch 1 taken 7217853 times.
7219574 if (glob_replace_regex) {
2664 1721 size_t orig_len = len;
2665 // Regex replace
2666
3/4
✓ Branch 0 taken 1721 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 248 times.
✓ Branch 3 taken 1473 times.
1721 if (!multi_reg_replace(glob_replace_regex, (char *)val, &len)) {
2667 248 val = glob_replace_regex->buf;
2668 } else {
2669 1473 len = orig_len;
2670 }
2671 }
2672 DYNAMIC_STRING ds_temp;
2673
1/2
✓ Branch 0 taken 7219574 times.
✗ Branch 1 not taken.
7219574 init_dynamic_string(&ds_temp, "", 512);
2674
2675 /* Store result from replace_result in ds_temp */
2676
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 7219406 times.
7219574 if (glob_replace)
2677
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 replace_strings_append(glob_replace, &ds_temp, val, len);
2678
2679 /*
2680 Call the replace_numeric_round function with the specified
2681 precision. It may be used along with replace_result, so use the
2682 output from replace_result as the input for replace_numeric_round.
2683 */
2684
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7219571 times.
7219574 if (glob_replace_numeric_round >= 0) {
2685 /* Copy the result from replace_result if it was used, into buffer */
2686
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ds_temp.length > 0) {
2687 char buffer[512];
2688 strcpy(buffer, ds_temp.str);
2689 dynstr_free(&ds_temp);
2690 init_dynamic_string(&ds_temp, "", 512);
2691 replace_numeric_round_append(glob_replace_numeric_round, &ds_temp,
2692 buffer, std::strlen(buffer));
2693 } else
2694
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 replace_numeric_round_append(glob_replace_numeric_round, &ds_temp,
2695 val, len);
2696 }
2697
2698
4/4
✓ Branch 0 taken 7219406 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 7219403 times.
✓ Branch 3 taken 3 times.
7219574 if (!glob_replace && glob_replace_numeric_round < 0)
2699
1/2
✓ Branch 0 taken 7219403 times.
✗ Branch 1 not taken.
7219403 dynstr_append_mem(&result, val, len);
2700 else
2701
1/2
✓ Branch 0 taken 171 times.
✗ Branch 1 not taken.
171 dynstr_append_mem(&result, ds_temp.str, std::strlen(ds_temp.str));
2702
1/2
✓ Branch 0 taken 7219574 times.
✗ Branch 1 not taken.
7219574 dynstr_free(&ds_temp);
2703 }
2704
1/2
✓ Branch 0 taken 7219574 times.
✗ Branch 1 not taken.
7219574 dynstr_append_mem(&result, "\t", 1);
2705 }
2706 7216495 end = result.str + result.length - 1;
2707 /* Evaluation should not recurse via backtick */
2708
1/2
✓ Branch 0 taken 7216495 times.
✗ Branch 1 not taken.
7216495 eval_expr(var, result.str, &end, false, false);
2709
1/2
✓ Branch 0 taken 7216495 times.
✗ Branch 1 not taken.
7216495 dynstr_free(&result);
2710 } else
2711
1/2
✓ Branch 0 taken 32565 times.
✗ Branch 1 not taken.
32565 eval_expr(var, "", nullptr);
2712
2713
1/2
✓ Branch 0 taken 7249060 times.
✗ Branch 1 not taken.
7249060 mysql_free_result_wrapper(res);
2714
2/2
✓ Branch 0 taken 7249060 times.
✓ Branch 1 taken 6957 times.
7256017 }
2715
2716 static void set_result_format_version(ulong new_version) {
2717 switch (new_version) {
2718 case 1:
2719 /* The first format */
2720 break;
2721 case 2:
2722 /* New format that also writes comments and empty lines
2723 from test file to result */
2724 break;
2725 default:
2726 die("Version format %lu has not yet been implemented", new_version);
2727 break;
2728 }
2729 opt_result_format_version = new_version;
2730 }
2731
2732 /*
2733 Set the result format version to use when generating
2734 the .result file
2735 */
2736
2737 static void do_result_format_version(struct st_command *command) {
2738 long version;
2739 static DYNAMIC_STRING ds_version;
2740 const struct command_arg result_format_args[] = {
2741 {"version", ARG_STRING, true, &ds_version, "Version to use"}};
2742
2743 DBUG_TRACE;
2744
2745 check_command_args(command, command->first_argument, result_format_args,
2746 sizeof(result_format_args) / sizeof(struct command_arg),
2747 ',');
2748
2749 /* Convert version number to int */
2750 if (!str2int(ds_version.str, 10, (long)0, (long)INT_MAX, &version))
2751 die("Invalid version number: '%s'", ds_version.str);
2752
2753 set_result_format_version(version);
2754
2755 dynstr_append(&ds_res, "result_format: ");
2756 dynstr_append_mem(&ds_res, ds_version.str, ds_version.length);
2757 dynstr_append(&ds_res, "\n");
2758 dynstr_free(&ds_version);
2759 }
2760
2761 /// Convert between error numbers and error names/strings.
2762 ///
2763 /// @code
2764 /// let $var = convert_error(ER_UNKNOWN_ERROR);
2765 /// let $var = convert_error(1234);
2766 /// @endcode
2767 ///
2768 /// The variable '$var' will be populated with error number if the
2769 /// argument is string. The variable var will be populated with error
2770 /// string if the argument is number.
2771 ///
2772 /// @param command Pointer to the st_command structure which holds the
2773 /// arguments and information for the command.
2774 /// @param var Pointer to VAR object containing a variable
2775 /// information.
2776 902 static void var_set_convert_error(struct st_command *command, VAR *var) {
2777 // The command->query contains the statement convert_error(1234)
2778 902 char *first = std::strchr(command->query, '(') + 1;
2779 902 char *last = std::strchr(command->query, ')');
2780
2781 // Denoting an empty string
2782
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 896 times.
902 if (last == first) {
2783
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 eval_expr(var, "0", nullptr);
2784 6 return;
2785 }
2786
2787 // If the string is an error string , it starts with 'E' as is the norm
2788
2/2
✓ Branch 0 taken 875 times.
✓ Branch 1 taken 21 times.
896 if (*first == 'E') {
2789
1/2
✓ Branch 0 taken 875 times.
✗ Branch 1 not taken.
875 std::string error_name(first, int(last - first));
2790
2/4
✓ Branch 0 taken 875 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 875 times.
✗ Branch 3 not taken.
875 int error = get_errcode_from_name(error_name);
2791
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 875 times.
875 if (error == -1) die("Unknown SQL error name '%s'.", error_name.c_str());
2792 char str[100];
2793 875 std::sprintf(str, "%d", error);
2794
1/2
✓ Branch 0 taken 875 times.
✗ Branch 1 not taken.
875 eval_expr(var, str, nullptr);
2795
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3 times.
896 } else if (my_isdigit(charset_info, *first)) {
2796 // Error number argument
2797 18 long int err = std::strtol(first, &last, 0);
2798
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 const char *err_name = get_errname_from_code(err);
2799
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 eval_expr(var, err_name, nullptr);
2800 } else {
2801 3 die("Invalid error in input");
2802 }
2803 }
2804
2805 /**
2806 Allocate memory for the buffer holding the string value of a variable.
2807
2808 @param var The variable
2809 @param length The number of string characters, not counting the \0.
2810 */
2811 42241 static void alloc_var(VAR *var, size_t length) {
2812 // Make space for '\0'
2813 42241 ++length;
2814
2/2
✓ Branch 0 taken 382 times.
✓ Branch 1 taken 41859 times.
42241 if (var->alloced_len < length) {
2815 // At least double the length, so we don't have to allocate so often.
2816
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 318 times.
382 if (length < var->alloced_len * 2) length = var->alloced_len * 2;
2817 382 var->str_val = (char *)my_realloc(PSI_NOT_INSTRUMENTED, var->str_val,
2818 length, MYF(MY_WME));
2819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 382 times.
382 if (!var->str_val) die("Out of memory");
2820 382 var->alloced_len = length;
2821 }
2822 42241 }
2823
2824 /**
2825 Process a "let $variable = escape(CHARACTERS,TEXT)" command.
2826
2827 This will parse the text starting after 'escape'. If parsing is
2828 successful, it inserts a backslash character before each character
2829 in 'TEXT' that occurs in 'CHARACTERS' and stores the result in
2830 $variable. If parsing fails, it prints an error message and aborts
2831 the program.
2832
2833 CHARACTERS is a string of at least one character, where ',' must not
2834 occur except as the first character. Newlines are not allowed.
2835 Backslashes are not treated as escape characters when parsing
2836 CHARACTERS, so escape(\',$x) will replace both backslashes and
2837 single quotes in $x.
2838
2839 @param command The st_command structure, where the 'first_argument'
2840 member points to the character just after 'escape'.
2841
2842 @param dst VAR object representing $variable
2843 */
2844 42254 static void var_set_escape(struct st_command *command, VAR *dst) {
2845 /*
2846 Parse and return the arguments.
2847
2848 This expects the format:
2849
2850 ^\([^\n\r][^,\n\r]*,.*\)$
2851
2852 I.e., an opening parenthesis, followed by a newline-free string of
2853 at least one character which does not have commas except possibly
2854 in the first character, followed by a comma, followed by an
2855 arbitrary string, followed by a closing parenthesis.
2856
2857 Returns a triple containing:
2858 - The first string,
2859 - the second string,
2860 - a bool that is false if the parsing succeeded; true if it failed.
2861 */
2862 42254 auto parse_args = [&]() -> auto {
2863 // command->first_argument contains '(characters,text)'
2864 42254 char *p = command->first_argument;
2865 // Find (
2866
2/2
✓ Branch 0 taken 42248 times.
✓ Branch 1 taken 6 times.
42254 if (*p == '(') {
2867 42248 ++p;
2868 // Find [^\n\r][^,\n\r]*
2869 42248 char *char_start = p;
2870
4/6
✓ Branch 0 taken 42248 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42247 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 42247 times.
✗ Branch 5 not taken.
42248 if (*p != '\0' && *p != '\n' && *p != '\r') {
2871 42247 ++p;
2872
6/8
✓ Branch 0 taken 78674 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 36430 times.
✓ Branch 3 taken 42244 times.
✓ Branch 4 taken 36430 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36430 times.
✗ Branch 7 not taken.
78677 while (*p != '\0' && *p != ',' && *p != '\n' && *p != '\r') ++p;
2873 // Find ,
2874
2/2
✓ Branch 0 taken 42244 times.
✓ Branch 1 taken 3 times.
42247 if (*p == ',') {
2875 42244 size_t char_len = p - char_start;
2876 42244 ++p;
2877 // Find .*$
2878 42244 char *text_start = p;
2879
2/2
✓ Branch 0 taken 2622395 times.
✓ Branch 1 taken 42244 times.
2664639 while (*p != '\0') ++p;
2880 // Find )
2881 42244 --p;
2882
2/2
✓ Branch 0 taken 42241 times.
✓ Branch 1 taken 3 times.
42244 if (*p == ')') {
2883 42241 size_t text_len = p - text_start;
2884
1/2
✓ Branch 0 taken 42241 times.
✗ Branch 1 not taken.
84482 return std::make_tuple(std::string(char_start, char_len),
2885
2/4
✓ Branch 0 taken 42241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42241 times.
✗ Branch 3 not taken.
126723 std::string(text_start, text_len), false);
2886 }
2887 }
2888 }
2889 }
2890
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
26 return std::make_tuple(std::string(), std::string(), true);
2891 42254 };
2892
2893 42254 std::string chars;
2894 42254 std::string src;
2895 bool error;
2896
1/2
✓ Branch 0 taken 42254 times.
✗ Branch 1 not taken.
42254 std::tie(chars, src, error) = parse_args();
2897 /*
2898 // This is the same, implemented with a regular expression.
2899 // Unfortunately it crashes on windows. Not sure but maybe a bug in
2900 // the regex library on windows?
2901 auto parse_args_regex = [&]() -> auto {
2902 // command->first_argument contains '(characters,text)'
2903 static const std::regex arg_re("^\\((.[^\\r\\n,]*),((?:.|[\\r\\n])*)\\)$",
2904 std::regex::optimize);
2905 // Parse arguments.
2906 std::cmatch arg_match;
2907 if (std::regex_search(command->first_argument, arg_match, arg_re))
2908 return std::make_tuple(std::string(arg_match[1]),
2909 std::string(arg_match[2]),
2910 false);
2911 return std::make_tuple(std::string(), std::string(), true);
2912 };
2913 std::string character_str2, src2;
2914 bool error2;
2915 std::tie(character_str2, src2, error2) = parse_args_regex();
2916 assert(character_str == character_str2);
2917 assert(src == src2);
2918 assert(error == error2);
2919 */
2920
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 42241 times.
42254 if (error)
2921 13 die("Invalid format of 'escape' arguments: <%.100s>",
2922 command->first_argument);
2923
2924 42241 auto begin = chars.begin();
2925 42241 auto end = chars.end();
2926 // Compute length of escaped string
2927 42241 auto dst_len = src.length();
2928
2/2
✓ Branch 0 taken 2580148 times.
✓ Branch 1 taken 42241 times.
2622389 for (char c : src)
2929
3/4
✓ Branch 0 taken 2580148 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48663 times.
✓ Branch 3 taken 2531485 times.
2580148 if (std::find(begin, end, c) != end) dst_len++;
2930 // Allocate space for escaped string
2931
1/2
✓ Branch 0 taken 42241 times.
✗ Branch 1 not taken.
42241 alloc_var(dst, dst_len);
2932 42241 auto dst_char = dst->str_val;
2933 // Compute escaped string
2934
2/2
✓ Branch 0 taken 2580148 times.
✓ Branch 1 taken 42241 times.
2622389 for (char c : src) {
2935
3/4
✓ Branch 0 taken 2580148 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48663 times.
✓ Branch 3 taken 2531485 times.
2580148 if (std::find(begin, end, c) != end) *dst_char++ = '\\';
2936 2580148 *dst_char++ = c;
2937 }
2938 42241 dst->str_val_len = dst_len;
2939 42241 }
2940
2941 /*
2942 Set variable from the result of a field in a query
2943
2944 This function is useful when checking for a certain value
2945 in the output from a query that can't be restricted to only
2946 return some values. A very good example of that is most SHOW
2947 commands.
2948
2949 SYNOPSIS
2950 var_set_query_get_value()
2951
2952 DESCRIPTION
2953 let $variable= query_get_value(<query to run>,<column name>,<row no>);
2954
2955 <query to run> - The query that should be sent to the server
2956 <column name> - Name of the column that holds the field be compared
2957 against the expected value
2958 <row no> - Number of the row that holds the field to be
2959 compared against the expected value
2960
2961 */
2962
2963 335243 static void var_set_query_get_value(struct st_command *command, VAR *var) {
2964 long row_no;
2965 335243 int col_no = -1;
2966 335243 MYSQL_RES *res = nullptr;
2967 335243 MYSQL *mysql = &cur_con->mysql;
2968
2969 static DYNAMIC_STRING ds_query;
2970 static DYNAMIC_STRING ds_col;
2971 static DYNAMIC_STRING ds_row;
2972 335243 const struct command_arg query_get_value_args[] = {
2973 {"query", ARG_STRING, true, &ds_query, "Query to run"},
2974 {"column name", ARG_STRING, true, &ds_col, "Name of column"},
2975 {"row number", ARG_STRING, true, &ds_row, "Number for row"}};
2976
2977
1/2
✓ Branch 0 taken 335243 times.
✗ Branch 1 not taken.
335243 DBUG_TRACE;
2978
2979
1/2
✓ Branch 0 taken 335240 times.
✗ Branch 1 not taken.
335243 strip_parentheses(command);
2980
3/8
✓ Branch 0 taken 335240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 335240 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 335240 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
335240 DBUG_PRINT("info", ("query: %s", command->query));
2981
1/2
✓ Branch 0 taken 335231 times.
✗ Branch 1 not taken.
335240 check_command_args(command, command->first_argument, query_get_value_args,
2982 sizeof(query_get_value_args) / sizeof(struct command_arg),
2983 ',');
2984
2985
3/8
✓ Branch 0 taken 335231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 335231 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 335231 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
335231 DBUG_PRINT("info", ("query: %s", ds_query.str));
2986
3/8
✓ Branch 0 taken 335231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 335231 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 335231 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
335231 DBUG_PRINT("info", ("col: %s", ds_col.str));
2987
2988 /* Convert row number to int */
2989
3/4
✓ Branch 0 taken 335231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 335228 times.
335231 if (!str2int(ds_row.str, 10, (long)0, (long)INT_MAX, &row_no))
2990 3 die("Invalid row number: '%s'", ds_row.str);
2991
3/8
✓ Branch 0 taken 335228 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 335228 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 335228 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
335228 DBUG_PRINT("info", ("row: %s, row_no: %ld", ds_row.str, row_no));
2992
1/2
✓ Branch 0 taken 335228 times.
✗ Branch 1 not taken.
335228 dynstr_free(&ds_row);
2993
2994 /* Remove any surrounding "'s from the query - if there is any */
2995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 335228 times.
335228 if (strip_surrounding(ds_query.str, '"', '"'))
2996 die("Mismatched \"'s around query '%s'", ds_query.str);
2997
2998 /* Run the query */
2999
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 335219 times.
335228 if (mysql_real_query_wrapper(mysql, ds_query.str,
3000
1/2
✓ Branch 0 taken 335228 times.
✗ Branch 1 not taken.
335228 static_cast<ulong>(ds_query.length))) {
3001
4/8
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
9 handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
3002 mysql_sqlstate(mysql), &ds_res);
3003 /* If error was acceptable, return empty string */
3004
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 dynstr_free(&ds_query);
3005
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 dynstr_free(&ds_col);
3006
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 eval_expr(var, "", nullptr);
3007 6 return;
3008 }
3009
3010
3/4
✓ Branch 0 taken 335219 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 335216 times.
335219 if (!(res = mysql_store_result_wrapper(mysql)))
3011 3 die("Query '%s' didn't return a result set", ds_query.str);
3012
3013 {
3014 /* Find column number from the given column name */
3015 uint i;
3016
1/2
✓ Branch 0 taken 335216 times.
✗ Branch 1 not taken.
335216 uint num_fields = mysql_num_fields(res);
3017
1/2
✓ Branch 0 taken 335216 times.
✗ Branch 1 not taken.
335216 MYSQL_FIELD *fields = mysql_fetch_fields(res);
3018
3019
2/2
✓ Branch 0 taken 2967243 times.
✓ Branch 1 taken 6 times.
2967249 for (i = 0; i < num_fields; i++) {
3020
2/2
✓ Branch 0 taken 335210 times.
✓ Branch 1 taken 2632033 times.
2967243 if (std::strcmp(fields[i].name, ds_col.str) == 0 &&
3021
1/2
✓ Branch 0 taken 335210 times.
✗ Branch 1 not taken.
335210 std::strlen(fields[i].name) == ds_col.length) {
3022 335210 col_no = i;
3023 335210 break;
3024 }
3025 }
3026
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 335210 times.
335216 if (col_no == -1) {
3027
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 mysql_free_result_wrapper(res);
3028 6 die("Could not find column '%s' in the result of '%s'", ds_col.str,
3029 ds_query.str);
3030 }
3031
3/8
✓ Branch 0 taken 335210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 335210 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 335210 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
335210 DBUG_PRINT("info", ("Found column %d with name '%s'", i, fields[i].name));
3032 }
3033
1/2
✓ Branch 0 taken 335210 times.
✗ Branch 1 not taken.
335210 dynstr_free(&ds_col);
3034
3035 {
3036 /* Get the value */
3037 MYSQL_ROW row;
3038 335210 long rows = 0;
3039 335210 const char *value = "No such row";
3040
3041
3/4
✓ Branch 0 taken 351905 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 316687 times.
✓ Branch 3 taken 35218 times.
351905 while ((row = mysql_fetch_row_wrapper(res))) {
3042
2/2
✓ Branch 0 taken 299992 times.
✓ Branch 1 taken 16695 times.
316687 if (++rows == row_no) {
3043
3/8
✓ Branch 0 taken 299992 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299992 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 299992 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
299992 DBUG_PRINT("info", ("At row %ld, column %d is '%s'", row_no, col_no,
3044 row[col_no]));
3045 /* Found the row to get */
3046
2/2
✓ Branch 0 taken 299803 times.
✓ Branch 1 taken 189 times.
299992 if (row[col_no])
3047 299803 value = row[col_no];
3048 else
3049 189 value = "NULL";
3050
3051 299992 break;
3052 }
3053 }
3054
1/2
✓ Branch 0 taken 335210 times.
✗ Branch 1 not taken.
335210 eval_expr(var, value, nullptr, false, false);
3055 }
3056
1/2
✓ Branch 0 taken 335210 times.
✗ Branch 1 not taken.
335210 dynstr_free(&ds_query);
3057
1/2
✓ Branch 0 taken 335210 times.
✗ Branch 1 not taken.
335210 mysql_free_result_wrapper(res);
3058
2/2
✓ Branch 0 taken 335210 times.
✓ Branch 1 taken 6 times.
335216 }
3059
3060 20247448 static void var_copy(VAR *dest, VAR *src) {
3061 20247448 dest->int_val = src->int_val;
3062 20247448 dest->is_int = src->is_int;
3063 20247448 dest->int_dirty = src->int_dirty;
3064
3065 /* Alloc/realloc data for str_val in dest */
3066
3/4
✓ Branch 0 taken 1903063 times.
✓ Branch 1 taken 18344385 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20247448 times.
22150511 if (dest->alloced_len < src->alloced_len &&
3067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1903063 times.
1903063 !(dest->str_val =
3068 1903063 dest->str_val
3069
1/2
✓ Branch 0 taken 1903063 times.
✗ Branch 1 not taken.
1903063 ? (char *)my_realloc(PSI_NOT_INSTRUMENTED, dest->str_val,
3070 src->alloced_len, MYF(MY_WME))
3071 : (char *)my_malloc(PSI_NOT_INSTRUMENTED, src->alloced_len,
3072 MYF(MY_WME))))
3073 die("Out of memory");
3074 else
3075 20247448 dest->alloced_len = src->alloced_len;
3076
3077 /* Copy str_val data to dest */
3078 20247448 dest->str_val_len = src->str_val_len;
3079
2/2
✓ Branch 0 taken 15614296 times.
✓ Branch 1 taken 4633152 times.
20247448 if (src->str_val_len) memcpy(dest->str_val, src->str_val, src->str_val_len);
3080 20247448 }
3081
3082 65055018 void eval_expr(VAR *v, const char *p, const char **p_end, bool open_end,
3083 bool do_eval) {
3084
1/2
✓ Branch 0 taken 65055018 times.
✗ Branch 1 not taken.
65055018 DBUG_TRACE;
3085
2/2
✓ Branch 0 taken 64679381 times.
✓ Branch 1 taken 375637 times.
65055018 if (p_end) {
3086
3/8
✓ Branch 0 taken 64679381 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64679381 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 64679381 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
64679381 DBUG_PRINT("enter", ("p: '%.*s'", (int)(*p_end - p), p));
3087 } else {
3088
3/8
✓ Branch 0 taken 375637 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 375637 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 375637 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
375637 DBUG_PRINT("enter", ("p: '%s'", p));
3089 }
3090 /* Skip to treat as pure string if no evaluation */
3091
2/2
✓ Branch 0 taken 7551705 times.
✓ Branch 1 taken 57503313 times.
65055018 if (!do_eval) goto NO_EVAL;
3092
3093
2/2
✓ Branch 0 taken 20247448 times.
✓ Branch 1 taken 37255865 times.
57503313 if (*p == '$') {
3094 VAR *vp;
3095 20247448 const char *expected_end = *p_end; // Remember var end
3096
3/6
✓ Branch 0 taken 20247448 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20247448 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20247448 times.
✗ Branch 5 not taken.
20247448 if ((vp = var_get(p, p_end, false, false))) var_copy(v, vp);
3097
3098 /* Apparently it is not safe to assume null-terminated string */
3099 20247448 v->str_val[v->str_val_len] = 0;
3100
3101 /* Make sure there was just a $variable and nothing else */
3102 20247448 const char *end = *p_end + 1;
3103
3/4
✓ Branch 0 taken 3614793 times.
✓ Branch 1 taken 16632655 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3614793 times.
20247448 if (end < expected_end && !open_end)
3104 die("Found junk '%.*s' after $variable in expression",
3105 (int)(expected_end - end - 1), end);
3106
3107 20247448 return;
3108 }
3109
3110
2/2
✓ Branch 0 taken 7256029 times.
✓ Branch 1 taken 29999836 times.
37255865 if (*p == '`') {
3111
1/2
✓ Branch 0 taken 7256017 times.
✗ Branch 1 not taken.
7256029 var_query_set(v, p, p_end);
3112 7256017 return;
3113 }
3114
3115 {
3116 auto parse_function =
3117 89328120 [&](const char *prefix,
3118 void (*parser)(struct st_command *, VAR *)) -> bool {
3119 89328120 const size_t len = std::strlen(prefix);
3120
2/2
✓ Branch 0 taken 378399 times.
✓ Branch 1 taken 88949721 times.
89328120 if (std::strncmp(p, prefix, len) == 0) {
3121 struct st_command command;
3122 378399 memset(&command, 0, sizeof(command));
3123 378399 command.query = const_cast<char *>(p);
3124 378399 command.first_word_len = len;
3125 378399 command.first_argument = command.query + len;
3126 378399 command.end = const_cast<char *>(*p_end);
3127
1/2
✓ Branch 0 taken 378356 times.
✗ Branch 1 not taken.
378399 parser(&command, v);
3128 378356 return true;
3129 }
3130 88949721 return false;
3131 29999836 };
3132
3133
3/4
✓ Branch 0 taken 29999809 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 335216 times.
✓ Branch 3 taken 29664593 times.
30042976 if (parse_function("query_get_value", var_set_query_get_value)) return;
3134
3/4
✓ Branch 0 taken 29664590 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 899 times.
✓ Branch 3 taken 29663691 times.
29664593 if (parse_function("convert_error", var_set_convert_error)) return;
3135
3/4
✓ Branch 0 taken 29663678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42241 times.
✓ Branch 3 taken 29621437 times.
29663691 if (parse_function("escape", var_set_escape)) return;
3136 }
3137
3138 37173142 NO_EVAL : {
3139 37173142 size_t new_val_len =
3140
3/4
✓ Branch 0 taken 36797505 times.
✓ Branch 1 taken 375637 times.
✓ Branch 2 taken 36797505 times.
✗ Branch 3 not taken.
37173142 (p_end && *p_end) ? static_cast<size_t>(*p_end - p) : std::strlen(p);
3141
2/2
✓ Branch 0 taken 2321342 times.
✓ Branch 1 taken 34851800 times.
37173142 if (new_val_len + 1 >= v->alloced_len) {
3142 static size_t MIN_VAR_ALLOC = 32;
3143 2321342 v->alloced_len =
3144
2/2
✓ Branch 0 taken 1536723 times.
✓ Branch 1 taken 784619 times.
2321342 (new_val_len < MIN_VAR_ALLOC - 1) ? MIN_VAR_ALLOC : new_val_len + 1;
3145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2321342 times.
2321342 if (!(v->str_val =
3146
2/2
✓ Branch 0 taken 2321172 times.
✓ Branch 1 taken 170 times.
4642514 v->str_val ? (char *)my_realloc(PSI_NOT_INSTRUMENTED, v->str_val,
3147
1/2
✓ Branch 0 taken 2321172 times.
✗ Branch 1 not taken.
2321172 v->alloced_len + 1, MYF(MY_WME))
3148 170 : (char *)my_malloc(PSI_NOT_INSTRUMENTED,
3149
1/2
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
170 v->alloced_len + 1, MYF(MY_WME))))
3150 die("Out of memory");
3151 }
3152 37173142 v->str_val_len = new_val_len;
3153 37173142 memcpy(v->str_val, p, new_val_len);
3154 37173142 v->str_val[new_val_len] = 0;
3155 37173142 var_check_int(v);
3156 }
3157
2/2
✓ Branch 0 taken 37173142 times.
✓ Branch 1 taken 27881821 times.
65054963 }
3158
3159 4118824 static int open_file(const char *name) {
3160 char buff[FN_REFLEN];
3161 size_t length;
3162
1/2
✓ Branch 0 taken 4118824 times.
✗ Branch 1 not taken.
4118824 DBUG_TRACE;
3163
3/8
✓ Branch 0 taken 4118824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4118824 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4118824 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4118824 DBUG_PRINT("enter", ("name: %s", name));
3164
3165 4118824 bool file_exists = false;
3166 /* Extract path from current file and try it as base first */
3167
3/4
✓ Branch 0 taken 4118824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4118803 times.
✓ Branch 3 taken 21 times.
4118824 if (dirname_part(buff, cur_file->file_name, &length)) {
3168
1/2
✓ Branch 0 taken 4118803 times.
✗ Branch 1 not taken.
4118803 strxmov(buff, buff, name, NullS);
3169
2/2
✓ Branch 0 taken 7705 times.
✓ Branch 1 taken 4111098 times.
4118803 if (access(buff, F_OK) == 0) {
3170
3/8
✓ Branch 0 taken 7705 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7705 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7705 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
7705 DBUG_PRINT("info", ("The file exists"));
3171 7705 name = buff;
3172 7705 file_exists = true;
3173 }
3174 }
3175
3176
7/8
✓ Branch 0 taken 4118824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4110129 times.
✓ Branch 3 taken 8695 times.
✓ Branch 4 taken 4108231 times.
✓ Branch 5 taken 1898 times.
✓ Branch 6 taken 4108231 times.
✓ Branch 7 taken 10593 times.
4118824 if (!test_if_hard_path(name) && !file_exists) {
3177
1/2
✓ Branch 0 taken 4108231 times.
✗ Branch 1 not taken.
4108231 strxmov(buff, opt_basedir, name, NullS);
3178 4108231 name = buff;
3179 }
3180
1/2
✓ Branch 0 taken 4118824 times.
✗ Branch 1 not taken.
4118824 fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
3181
3182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4118821 times.
4118824 if (cur_file == file_stack_end) die("Source directives are nesting too deep");
3183 4118821 cur_file++;
3184
3/4
✓ Branch 0 taken 4118821 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4118818 times.
4118821 if (!(cur_file->file = fopen(buff, "rb"))) {
3185 3 cur_file--;
3186 3 die("Could not open '%s' for reading, errno: %d", buff, errno);
3187 }
3188
1/2
✓ Branch 0 taken 4118818 times.
✗ Branch 1 not taken.
4118818 cur_file->file_name = my_strdup(PSI_NOT_INSTRUMENTED, buff, MYF(MY_FAE));
3189 4118818 cur_file->lineno = 1;
3190 4118818 return 0;
3191 4118818 }
3192
3193 /*
3194 Source and execute the given file
3195
3196 SYNOPSIS
3197 do_source()
3198 query called command
3199
3200 DESCRIPTION
3201 source <file_name>
3202
3203 Open the file <file_name> and execute it
3204
3205 */
3206
3207 17652382 static void do_source(struct st_command *command) {
3208 static DYNAMIC_STRING ds_filename;
3209 17652382 const struct command_arg source_args[] = {
3210 {"filename", ARG_STRING, true, &ds_filename, "File to source"}};
3211
1/2
✓ Branch 0 taken 17652382 times.
✗ Branch 1 not taken.
17652382 DBUG_TRACE;
3212
3213
1/2
✓ Branch 0 taken 17652379 times.
✗ Branch 1 not taken.
17652382 check_command_args(command, command->first_argument, source_args,
3214 sizeof(source_args) / sizeof(struct command_arg), ' ');
3215
3216 /*
3217 If this file has already been sourced, don't source it again.
3218 It's already available in the q_lines cache.
3219 */
3220
2/2
✓ Branch 0 taken 4118824 times.
✓ Branch 1 taken 13533555 times.
17652379 if (parser.current_line < (parser.read_lines - 1))
3221 ; /* Do nothing */
3222 else {
3223
3/8
✓ Branch 0 taken 4118824 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4118824 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4118824 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
4118824 DBUG_PRINT("info", ("sourcing file: %s", ds_filename.str));
3224
1/2
✓ Branch 0 taken 4118818 times.
✗ Branch 1 not taken.
4118824 open_file(ds_filename.str);
3225 }
3226
3227
1/2
✓ Branch 0 taken 17652373 times.
✗ Branch 1 not taken.
17652373 dynstr_free(&ds_filename);
3228 17652373 }
3229
3230 34133 static FILE *my_popen(DYNAMIC_STRING *ds_cmd, const char *mode,
3231 struct st_command *command [[maybe_unused]]) {
3232 #ifdef _WIN32
3233 /*
3234 --execw is for tests executing commands containing non-ASCII characters.
3235
3236 To correctly start such a program on Windows, we need to use the "wide"
3237 version of popen, with prior translation of the command line from
3238 the file character set to wide string. We use the current value
3239 of --character_set as a file character set, so before using --execw
3240 make sure to set --character_set properly.
3241
3242 If we use the non-wide version of popen, Windows internally
3243 converts command line from the current ANSI code page to wide string.
3244 In case when character set of the command line does not match the
3245 current ANSI code page, non-ASCII characters get garbled in most cases.
3246
3247 On Linux, the command line passed to popen() is considered
3248 as a binary string, no any internal to-wide and from-wide
3249 character set conversion happens, so we don't need to do anything.
3250 On Linux --execw is just a synonym to --exec.
3251
3252 For simplicity, assume that command line is limited to 4KB
3253 (like in cmd.exe) and that mode at most 10 characters.
3254 */
3255 if (command->type == Q_EXECW) {
3256 wchar_t wcmd[4096];
3257 wchar_t wmode[10];
3258 const char *cmd = ds_cmd->str;
3259 uint dummy_errors;
3260 size_t len;
3261 len = my_convert((char *)wcmd, sizeof(wcmd) - sizeof(wcmd[0]),
3262 &my_charset_utf16le_bin, ds_cmd->str,
3263 std::strlen(ds_cmd->str), charset_info, &dummy_errors);
3264 wcmd[len / sizeof(wchar_t)] = 0;
3265 len = my_convert((char *)wmode, sizeof(wmode) - sizeof(wmode[0]),
3266 &my_charset_utf16le_bin, mode, std::strlen(mode),
3267 charset_info, &dummy_errors);
3268 wmode[len / sizeof(wchar_t)] = 0;
3269 return _wpopen(wcmd, wmode);
3270 }
3271 #endif /* _WIN32 */
3272
3273 34133 errno = 0;
3274 34133 FILE *file = popen(ds_cmd->str, mode);
3275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34133 times.
34133 if (file == NULL) {
3276 if (errno != 0) {
3277 fprintf(stderr, "mysqltest: popen failed with errno %d (%s)\n", errno,
3278 strerror(errno));
3279 } else {
3280 fprintf(stderr,
3281 "mysqltest: popen returned NULL without setting errno "
3282 "(out-of-memory?)\n");
3283 }
3284 }
3285 34133 return file;
3286 }
3287
3288 50135 static void init_builtin_echo(void) {
3289 #ifdef _WIN32
3290 size_t echo_length;
3291
3292 /* Look for "echo.exe" in same dir as mysqltest was started from */
3293 dirname_part(builtin_echo, my_progname, &echo_length);
3294 fn_format(builtin_echo, ".\\echo.exe", builtin_echo, "", MYF(MY_REPLACE_DIR));
3295
3296 /* Make sure echo.exe exists */
3297 if (access(builtin_echo, F_OK) != 0) builtin_echo[0] = 0;
3298 return;
3299
3300 #else
3301
3302 50135 builtin_echo[0] = 0;
3303 50135 return;
3304
3305 #endif
3306 }
3307
3308 /*
3309 Replace a substring
3310
3311 SYNOPSIS
3312 replace
3313 ds_str The string to search and perform the replace in
3314 search_str The string to search for
3315 search_len Length of the string to search for
3316 replace_str The string to replace with
3317 replace_len Length of the string to replace with
3318
3319 RETURN
3320 0 String replaced
3321 1 Could not find search_str in str
3322 */
3323
3324 38387 static int replace(DYNAMIC_STRING *ds_str, const char *search_str,
3325 size_t search_len, const char *replace_str,
3326 size_t replace_len) {
3327 DYNAMIC_STRING ds_tmp;
3328 38387 const char *start = strstr(ds_str->str, search_str);
3329
2/2
✓ Branch 0 taken 34133 times.
✓ Branch 1 taken 4254 times.
38387 if (!start) return 1;
3330
1/2
✓ Branch 0 taken 4254 times.
✗ Branch 1 not taken.
4254 init_dynamic_string(&ds_tmp, "", ds_str->length + replace_len);
3331
1/2
✓ Branch 0 taken 4254 times.
✗ Branch 1 not taken.
4254 dynstr_append_mem(&ds_tmp, ds_str->str, start - ds_str->str);
3332
1/2
✓ Branch 0 taken 4254 times.
✗ Branch 1 not taken.
4254 dynstr_append_mem(&ds_tmp, replace_str, replace_len);
3333
1/2
✓ Branch 0 taken 4254 times.
✗ Branch 1 not taken.
4254 dynstr_append(&ds_tmp, start + search_len);
3334
1/2
✓ Branch 0 taken 4254 times.
✗ Branch 1 not taken.
4254 dynstr_set(ds_str, ds_tmp.str);
3335
1/2
✓ Branch 0 taken 4254 times.
✗ Branch 1 not taken.
4254 dynstr_free(&ds_tmp);
3336 4254 return 0;
3337 }
3338
3339 #ifdef _WIN32
3340 /**
3341 Replace CRLF sequence with LF in place.
3342
3343 This function is required as a workaround for a bug in the Microsoft
3344 C runtime library introduced in Visual Studio 2015.
3345 See bug#22608247 and bug#22811243
3346
3347 @param buf Null terminated buffer.
3348 */
3349 static void replace_crlf_with_lf(char *buf) {
3350 char *replace = buf;
3351 while (*buf) {
3352 *replace = *buf++;
3353 if (!((*replace == '\x0D') && (*buf == '\x0A'))) {
3354 replace++;
3355 }
3356 }
3357 *replace = '\x0';
3358 }
3359 #endif
3360
3361 /// Execute the shell command using the popen() library call. References
3362 /// to variables within the command are replaced with the corresponding
3363 /// values. Use “\\$” to specify a literal “$” character.
3364 ///
3365 /// The error code returned from the subprocess is checked against the
3366 /// expected error array, previously set with the --error command. It can
3367 /// thus be used to execute a command that shall fail.
3368 ///
3369 /// @code
3370 /// exec command [args]
3371 /// @endcode
3372 ///
3373 /// @param command Pointer to the st_command structure which holds the
3374 /// arguments and information for the command.
3375 /// @param run_in_background Specifies if command should be run in background.
3376 /// In such case we don't wait nor attempt to read the
3377 /// output.
3378 ///
3379 /// @note
3380 /// It is recommended to use mysqltest command(s) like "remove_file"
3381 /// instead of executing the shell commands using 'exec' command.
3382 34136 static void do_exec(struct st_command *command, bool run_in_background) {
3383
1/2
✓ Branch 0 taken 34136 times.
✗ Branch 1 not taken.
34136 DBUG_TRACE;
3384
3385 34136 const char *cmd = command->first_argument;
3386
3/8
✓ Branch 0 taken 34136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34136 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34136 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
34136 DBUG_PRINT("enter", ("cmd: '%s'", cmd));
3387
3388 // Skip leading space
3389
3/4
✓ Branch 0 taken 34133 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 34133 times.
34136 while (*cmd && my_isspace(charset_info, *cmd)) cmd++;
3390
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 34133 times.
34136 if (!*cmd) die("Missing argument in exec");
3391 34133 command->last_argument = command->end;
3392
3393 DYNAMIC_STRING ds_cmd;
3394
1/2
✓ Branch 0 taken 34133 times.
✗ Branch 1 not taken.
34133 init_dynamic_string(&ds_cmd, nullptr, command->query_len + 256);
3395
3396 // Eval the command, thus replacing all environment variables
3397
1/2
✓ Branch 0 taken 34133 times.
✗ Branch 1 not taken.
34133 do_eval(&ds_cmd, cmd, command->end, !is_windows);
3398
3399 // Check if echo should be replaced with "builtin" echo
3400
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 34133 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
34133 if (builtin_echo[0] && std::strncmp(cmd, "echo", 4) == 0) {
3401 // Replace echo with our "builtin" echo
3402 replace(&ds_cmd, "echo", 4, builtin_echo, std::strlen(builtin_echo));
3403 }
3404
3405 #ifdef _WIN32
3406 // Replace "/dev/null" with NUL
3407 while (replace(&ds_cmd, "/dev/null", 9, "NUL", 3) == 0)
3408 ;
3409
3410 // Replace "closed stdout" with non existing output fd
3411 while (replace(&ds_cmd, ">&-", 3, ">&4", 3) == 0)
3412 ;
3413 #endif
3414
3415
2/2
✓ Branch 0 taken 10648 times.
✓ Branch 1 taken 23485 times.
34133 if (run_in_background) {
3416 /* Add an invocation of "START /B" on Windows, append " &" on Linux*/
3417 DYNAMIC_STRING ds_tmp;
3418 #ifdef WIN32
3419 init_dynamic_string(&ds_tmp, "START /B ", ds_cmd.length + 9);
3420 dynstr_append_mem(&ds_tmp, ds_cmd.str, ds_cmd.length);
3421 #else
3422
1/2
✓ Branch 0 taken 10648 times.
✗ Branch 1 not taken.
10648 init_dynamic_string(&ds_tmp, ds_cmd.str, ds_cmd.length + 2);
3423
1/2
✓ Branch 0 taken 10648 times.
✗ Branch 1 not taken.
10648 dynstr_append_mem(&ds_tmp, " &", 2);
3424 #endif
3425
1/2
✓ Branch 0 taken 10648 times.
✗ Branch 1 not taken.
10648 dynstr_set(&ds_cmd, ds_tmp.str);
3426
1/2
✓ Branch 0 taken 10648 times.
✗ Branch 1 not taken.
10648 dynstr_free(&ds_tmp);
3427 }
3428
3429 // exec command is interpreted externally and will not take newlines
3430
3/4
✓ Branch 0 taken 38387 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4254 times.
✓ Branch 3 taken 34133 times.
38387 while (replace(&ds_cmd, "\n", 1, " ", 1) == 0)
3431 ;
3432
3433
3/8
✓ Branch 0 taken 34133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34133 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34133 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
34133 DBUG_PRINT("info",
3434 ("Executing '%s' as '%s'", command->first_argument, ds_cmd.str));
3435
3436 #ifdef WIN32
3437 // Open pipe in binary mode as part of handling Microsoft _read bug.
3438 // See bug#22608247 and bug#22811243
3439 const char *mode = "rb";
3440 #else
3441 34133 const char *mode = "r";
3442 #endif
3443 FILE *res_file;
3444
3/6
✓ Branch 0 taken 34133 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 34133 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 34133 times.
34133 if (!(res_file = my_popen(&ds_cmd, mode, command)) &&
3445 command->abort_on_error) {
3446 dynstr_free(&ds_cmd);
3447 die("popen(\"%s\", \"r\") failed", command->first_argument);
3448 }
3449
3450
2/2
✓ Branch 0 taken 23485 times.
✓ Branch 1 taken 10648 times.
34133 if (!run_in_background) {
3451 char buf[512];
3452 23485 std::string str;
3453
3/4
✓ Branch 0 taken 237821 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 214336 times.
✓ Branch 3 taken 23485 times.
237821 while (std::fgets(buf, sizeof(buf), res_file)) {
3454
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 214335 times.
214336 if (std::strlen(buf) < 1) continue;
3455
3456 #ifdef WIN32
3457 // Replace CRLF char with LF.
3458 // See bug#22608247 and bug#22811243
3459 assert(!std::strcmp(mode, "rb"));
3460 replace_crlf_with_lf(buf);
3461 #endif
3462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 214335 times.
214335 if (trace_exec) {
3463 fprintf(stdout, "%s", buf);
3464 fflush(stdout);
3465 }
3466
2/2
✓ Branch 0 taken 36185 times.
✓ Branch 1 taken 178150 times.
214335 if (disable_result_log) {
3467 36185 buf[std::strlen(buf) - 1] = 0;
3468
3/8
✓ Branch 0 taken 36185 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36185 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36185 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
36185 DBUG_PRINT("exec_result", ("%s", buf));
3469 } else {
3470 // Read the file line by line. Check if the buffer read from the
3471 // file ends with EOL character.
3472
2/2
✓ Branch 0 taken 567 times.
✓ Branch 1 taken 177583 times.
178150 if ((buf[std::strlen(buf) - 1] != '\n' &&
3473
2/2
✓ Branch 0 taken 563 times.
✓ Branch 1 taken 4 times.
567 std::strlen(buf) < (sizeof(buf) - 1)) ||
3474
2/2
✓ Branch 0 taken 177583 times.
✓ Branch 1 taken 563 times.
178146 (buf[std::strlen(buf) - 1] == '\n')) {
3475 // Found EOL
3476
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 177314 times.
177587 if (str.length()) {
3477 // Temporary string exists, append the current buffer read
3478 // to the temporary string.
3479
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 str.append(buf);
3480
1/2
✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
273 replace_dynstr_append(&ds_res, str.c_str());
3481 273 str.clear();
3482 } else {
3483 // Entire line is read at once
3484
1/2
✓ Branch 0 taken 177314 times.
✗ Branch 1 not taken.
177314 replace_dynstr_append(&ds_res, buf);
3485 }
3486 } else {
3487 // The buffer read from the file doesn't end with EOL character,
3488 // store it in a temporary string.
3489
1/2
✓ Branch 0 taken 563 times.
✗ Branch 1 not taken.
563 str.append(buf);
3490 }
3491 }
3492 }
3493 23485 }
3494
3495 34133 std::uint32_t status = 0;
3496
1/2
✓ Branch 0 taken 34133 times.
✗ Branch 1 not taken.
34133 int error = pclose(res_file);
3497
3498
2/2
✓ Branch 0 taken 1795 times.
✓ Branch 1 taken 32338 times.
34133 if (error != 0) {
3499 #ifdef _WIN32
3500 status = WEXITSTATUS(error);
3501 #else
3502
1/2
✓ Branch 0 taken 1795 times.
✗ Branch 1 not taken.
1795 if (error > 0) {
3503 // Do the same as many shells here: show SIGKILL as 137
3504
2/2
✓ Branch 0 taken 1791 times.
✓ Branch 1 taken 4 times.
1795 if (WIFEXITED(error))
3505 1791 status = WEXITSTATUS(error);
3506
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 else if (WIFSIGNALED(error))
3507 4 status = 0x80 + WTERMSIG(error);
3508 }
3509 #endif
3510
3511
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1781 times.
1795 if (command->abort_on_error) {
3512 14 log_msg("exec of '%s' failed, error: %d, status: %d, errno: %d.",
3513
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 ds_cmd.str, error, status, errno);
3514
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 dynstr_free(&ds_cmd);
3515 14 die("Command \"%s\" failed.\n\nOutput from before failure:\n%s",
3516 command->first_argument, ds_res.str);
3517 }
3518
3519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1781 times.
1781 if (status == 0) status = error;
3520 }
3521
3522
1/2
✓ Branch 0 taken 34119 times.
✗ Branch 1 not taken.
34119 dynstr_free(&ds_cmd);
3523
1/2
✓ Branch 0 taken 34117 times.
✗ Branch 1 not taken.
34119 handle_command_error(command, status);
3524
3525 // Save error code
3526
1/2
✓ Branch 0 taken 34117 times.
✗ Branch 1 not taken.
34117 save_error_code(error);
3527 34117 }
3528
3529 enum enum_operator { DO_DEC, DO_INC };
3530
3531 /// Template function that frees memory of the dynamic string
3532 /// passed to the function.
3533 ///
3534 /// @param val Dynamic string whose memory needs to be freed.
3535 template <typename T>
3536 254050 static void free_dynamic_strings(T *val) {
3537 254050 dynstr_free(val);
3538 254050 }
3539
3540 /// Frees the memory of dynamic strings passed to the function.
3541 /// It accepts a variable number of dynamic strings, and through
3542 /// recursion, frees the memory. The other template function
3543 /// which calls dynstr_free() is called here.
3544 ///
3545 /// @param first The dynamic string passed to the function which
3546 /// gets freed using dynstr_free().
3547 /// @param rest Rest of the dynamic strings which are passed to
3548 /// the function, through recursion, end up being
3549 /// freed by dynstr_free().
3550 template <typename T1, typename... T2>
3551 259684 static void free_dynamic_strings(T1 *first, T2 *... rest) {
3552 259684 free_dynamic_strings(first);
3553 259684 free_dynamic_strings(rest...);
3554 259684 }
3555
3556 /*
3557 Decrease or increase the value of a variable
3558
3559 SYNOPSIS
3560 do_modify_var()
3561 query called command
3562 op operation to perform on the var
3563
3564 DESCRIPTION
3565 dec $var_name
3566 inc $var_name
3567
3568 */
3569
3570 3604849 static int do_modify_var(struct st_command *command, enum enum_operator op) {
3571 3604849 const char *p = command->first_argument;
3572 VAR *v;
3573
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3604843 times.
3604849 if (!*p)
3574 6 die("Missing argument to %.*s", static_cast<int>(command->first_word_len),
3575 command->query);
3576
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3604837 times.
3604843 if (*p != '$')
3577 6 die("The argument to %.*s must be a variable (start with $)",
3578 6 static_cast<int>(command->first_word_len), command->query);
3579
1/2
✓ Branch 0 taken 3604837 times.
✗ Branch 1 not taken.
3604837 v = var_get(p, &p, true, false);
3580
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3604819 times.
3604837 if (!v->is_int) die("Cannot perform inc/dec on a non-numeric value");
3581
2/3
✓ Branch 0 taken 2540662 times.
✓ Branch 1 taken 1064157 times.
✗ Branch 2 not taken.
3604819 switch (op) {
3582 2540662 case DO_DEC:
3583 2540662 v->int_val--;
3584 2540662 break;
3585 1064157 case DO_INC:
3586 1064157 v->int_val++;
3587 1064157 break;
3588 default:
3589 die("Invalid operator to do_modify_var");
3590 break;
3591 }
3592 3604819 v->int_dirty = true;
3593 3604819 command->last_argument = const_cast<char *>(++p);
3594 3604819 return 0;
3595 }
3596
3597 /// Removes the file passed as the argument and retries a specified
3598 /// number of times, if it is unsuccessful.
3599 ///
3600 /// @param command Pointer to the st_command structure which holds the
3601 /// arguments and information for the command.
3602 107911 static void do_remove_file(struct st_command *command) {
3603 int error;
3604 static DYNAMIC_STRING ds_filename;
3605 static DYNAMIC_STRING ds_retry;
3606
3607 107911 const struct command_arg rm_args[] = {
3608 {"filename", ARG_STRING, true, &ds_filename, "File to delete"},
3609 {"retry", ARG_STRING, false, &ds_retry, "Number of retries"}};
3610
1/2
✓ Branch 0 taken 107911 times.
✗ Branch 1 not taken.
107911 DBUG_TRACE;
3611
3612
1/2
✓ Branch 0 taken 107908 times.
✗ Branch 1 not taken.
107911 check_command_args(command, command->first_argument, rm_args,
3613 sizeof(rm_args) / sizeof(struct command_arg), ' ');
3614
3615 // Check if the retry value is passed, and if it is an integer
3616 107908 int retry = 0;
3617
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 107881 times.
107908 if (ds_retry.length) {
3618
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 retry = get_int_val(ds_retry.str);
3619
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 12 times.
27 if (retry < 0) {
3620 // In case of invalid retry, copy the value passed to print later
3621 char buf[32];
3622
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strmake(buf, ds_retry.str, sizeof(buf) - 1);
3623
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 free_dynamic_strings(&ds_filename, &ds_retry);
3624 15 die("Invalid value '%s' for retry argument given to remove_file "
3625 "command.",
3626 buf);
3627 }
3628 }
3629
3630
3/8
✓ Branch 0 taken 107893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 107893 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 107893 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
107893 DBUG_PRINT("info", ("removing file: %s", ds_filename.str));
3631
1/2
✓ Branch 0 taken 107893 times.
✗ Branch 1 not taken.
107893 error = my_delete(ds_filename.str, MYF(0)) != 0;
3632
3633 /*
3634 If the remove command fails due to an environmental issue, the command can
3635 be retried a specified number of times before throwing an error.
3636 */
3637
3/4
✓ Branch 0 taken 35243 times.
✓ Branch 1 taken 72650 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35243 times.
107893 for (int i = 0; error && (i < retry); i++) {
3638 my_sleep(1000 * 1000);
3639 error = my_delete(ds_filename.str, MYF(0)) != 0;
3640 }
3641
3642
1/2
✓ Branch 0 taken 107890 times.
✗ Branch 1 not taken.
107893 handle_command_error(command, error);
3643
1/2
✓ Branch 0 taken 107890 times.
✗ Branch 1 not taken.
107890 free_dynamic_strings(&ds_filename, &ds_retry);
3644 107890 }
3645
3646 /// Removes the files in the specified directory, by matching the
3647 /// file name pattern. Retry of the command can happen optionally with
3648 /// an interval of one second between each retry if the command fails.
3649 ///
3650 /// @param command Pointer to the st_command structure which holds the
3651 /// arguments and information for the command.
3652 671 static void do_remove_files_wildcard(struct st_command *command) {
3653 671 int error = 0;
3654 uint i;
3655 MY_DIR *dir_info;
3656 FILEINFO *file;
3657 char dir_separator[2];
3658 static DYNAMIC_STRING ds_directory;
3659 static DYNAMIC_STRING ds_wild;
3660 static DYNAMIC_STRING ds_retry;
3661 char dirname[FN_REFLEN];
3662
3663 671 const struct command_arg rm_args[] = {
3664 {"directory", ARG_STRING, true, &ds_directory,
3665 "Directory containing files to delete"},
3666 {"pattern", ARG_STRING, true, &ds_wild, "File pattern to delete"},
3667 {"retry", ARG_STRING, false, &ds_retry, "Number of retries"}};
3668
1/2
✓ Branch 0 taken 671 times.
✗ Branch 1 not taken.
671 DBUG_TRACE;
3669
3670
1/2
✓ Branch 0 taken 665 times.
✗ Branch 1 not taken.
671 check_command_args(command, command->first_argument, rm_args,
3671 sizeof(rm_args) / sizeof(struct command_arg), ' ');
3672
1/2
✓ Branch 0 taken 665 times.
✗ Branch 1 not taken.
665 fn_format(dirname, ds_directory.str, "", "", MY_UNPACK_FILENAME);
3673
3674 // Check if the retry value is passed, and if it is an integer
3675 665 int retry = 0;
3676
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 647 times.
665 if (ds_retry.length) {
3677
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 retry = get_int_val(ds_retry.str);
3678
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (retry < 0) {
3679 // In case of invalid retry, copy the value passed to print later
3680 char buf[32];
3681
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strmake(buf, ds_retry.str, sizeof(buf) - 1);
3682
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 free_dynamic_strings(&ds_directory, &ds_wild, &ds_retry);
3683 15 die("Invalid value '%s' for retry argument given to "
3684 "remove_files_wildcard command.",
3685 buf);
3686 }
3687 }
3688
3689 static DYNAMIC_STRING ds_file_to_remove;
3690
3/8
✓ Branch 0 taken 650 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 650 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 650 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
650 DBUG_PRINT("info", ("listing directory: %s", dirname));
3691 /* Note that my_dir sorts the list if not given any flags */
3692
3/4
✓ Branch 0 taken 650 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 644 times.
650 if (!(dir_info = my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT)))) {
3693 6 error = 1;
3694 6 goto end;
3695 }
3696
1/2
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
644 init_dynamic_string(&ds_file_to_remove, dirname, 1024);
3697 644 dir_separator[0] = FN_LIBCHAR;
3698 644 dir_separator[1] = 0;
3699
1/2
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
644 dynstr_append(&ds_file_to_remove, dir_separator);
3700
3701 size_t length;
3702 /* Storing the length of the path to the file, so it can be reused */
3703 644 length = ds_file_to_remove.length;
3704
2/2
✓ Branch 0 taken 8463 times.
✓ Branch 1 taken 644 times.
9107 for (i = 0; i < (uint)dir_info->number_off_files; i++) {
3705 8463 ds_file_to_remove.length = length;
3706 8463 file = dir_info->dir_entry + i;
3707 /* Remove only regular files, i.e. no directories etc. */
3708 /* if (!MY_S_ISREG(file->mystat->st_mode)) */
3709 /* MY_S_ISREG does not work here on Windows, just skip directories */
3710
2/2
✓ Branch 0 taken 2328 times.
✓ Branch 1 taken 6135 times.
8463 if (MY_S_ISDIR(file->mystat->st_mode)) continue;
3711
2/2
✓ Branch 0 taken 3119 times.
✓ Branch 1 taken 3016 times.
6135 if (wild_compare_full(file->name, std::strlen(file->name), ds_wild.str,
3712
1/2
✓ Branch 0 taken 6135 times.
✗ Branch 1 not taken.
6135 std::strlen(ds_wild.str), false, 0, '?', '*'))
3713 3119 continue;
3714 /* Not required as the var ds_file_to_remove.length already has the
3715 length in canonnicalized form */
3716 /* ds_file_to_remove.length= ds_directory.length + 1;
3717 ds_file_to_remove.str[ds_directory.length + 1]= 0; */
3718
1/2
✓ Branch 0 taken 3016 times.
✗ Branch 1 not taken.
3016 dynstr_append(&ds_file_to_remove, file->name);
3719
3/8
✓ Branch 0 taken 3016 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3016 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3016 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3016 DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str));
3720
1/2
✓ Branch 0 taken 3016 times.
✗ Branch 1 not taken.
3016 error = my_delete(ds_file_to_remove.str, MYF(0)) != 0;
3721
3722 /*
3723 If the remove command fails due to an environmental issue, the command
3724 can be retried a specified number of times before throwing an error.
3725 */
3726
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3016 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3016 for (int j = 0; error && (j < retry); j++) {
3727 my_sleep(1000 * 1000);
3728 error = my_delete(ds_file_to_remove.str, MYF(0)) != 0;
3729 }
3730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3016 times.
3016 if (error) break;
3731 }
3732
1/2
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
644 my_dirend(dir_info);
3733
3734 650 end:
3735
1/2
✓ Branch 0 taken 650 times.
✗ Branch 1 not taken.
650 handle_command_error(command, error);
3736
1/2
✓ Branch 0 taken 650 times.
✗ Branch 1 not taken.
650 free_dynamic_strings(&ds_directory, &ds_wild, &ds_file_to_remove, &ds_retry);
3737 650 }
3738
3739 /// Copy the source file to destination file. Copy will fail if the
3740 /// destination file exists. Retry of the command can happen optionally with
3741 /// an interval of one second between each retry if the command fails.
3742 ///
3743 /// @param command Pointer to the st_command structure which holds the
3744 /// arguments and information for the command.
3745 3721 static void do_copy_file(struct st_command *command) {
3746 int error;
3747 static DYNAMIC_STRING ds_from_file;
3748 static DYNAMIC_STRING ds_to_file;
3749 static DYNAMIC_STRING ds_retry;
3750
3751 3721 const struct command_arg copy_file_args[] = {
3752 {"from_file", ARG_STRING, true, &ds_from_file, "Filename to copy from"},
3753 {"to_file", ARG_STRING, true, &ds_to_file, "Filename to copy to"},
3754 {"retry", ARG_STRING, false, &ds_retry, "Number of retries"}};
3755
1/2
✓ Branch 0 taken 3721 times.
✗ Branch 1 not taken.
3721 DBUG_TRACE;
3756
3757
1/2
✓ Branch 0 taken 3715 times.
✗ Branch 1 not taken.
3721 check_command_args(command, command->first_argument, copy_file_args,
3758 sizeof(copy_file_args) / sizeof(struct command_arg), ' ');
3759
3760 // Check if the retry value is passed, and if it is an integer
3761 3715 int retry = 0;
3762
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 3697 times.
3715 if (ds_retry.length) {
3763
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 retry = get_int_val(ds_retry.str);
3764
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (retry < 0) {
3765 // In case of invalid retry, copy the value passed to print later
3766 char buf[32];
3767
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strmake(buf, ds_retry.str, sizeof(buf) - 1);
3768
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 free_dynamic_strings(&ds_from_file, &ds_to_file, &ds_retry);
3769 15 die("Invalid value '%s' for retry argument given to copy_file "
3770 "command.",
3771 buf);
3772 }
3773 }
3774
3775
3/8
✓ Branch 0 taken 3700 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3700 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3700 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3700 DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str));
3776 /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */
3777
1/2
✓ Branch 0 taken 3700 times.
✗ Branch 1 not taken.
3700 error = (my_copy(ds_from_file.str, ds_to_file.str,
3778 3700 MYF(MY_DONT_OVERWRITE_FILE | MY_HOLD_ORIGINAL_MODES)) != 0);
3779
3780 /*
3781 If the copy command fails due to an environmental issue, the command can
3782 be retried a specified number of times before throwing an error.
3783 */
3784
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3700 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3700 for (int i = 0; error && (i < retry); i++) {
3785 my_sleep(1000 * 1000);
3786 error =
3787 (my_copy(ds_from_file.str, ds_to_file.str,
3788 MYF(MY_DONT_OVERWRITE_FILE | MY_HOLD_ORIGINAL_MODES)) != 0);
3789 }
3790
3791
1/2
✓ Branch 0 taken 3700 times.
✗ Branch 1 not taken.
3700 handle_command_error(command, error);
3792
1/2
✓ Branch 0 taken 3700 times.
✗ Branch 1 not taken.
3700 free_dynamic_strings(&ds_from_file, &ds_to_file, &ds_retry);
3793 3700 }
3794
3795 /*
3796 SYNOPSIS
3797 recursive_copy
3798 ds_source - pointer to dynamic string containing source
3799 directory information
3800 ds_destination - pointer to dynamic string containing destination
3801 directory information
3802
3803 DESCRIPTION
3804 Recursive copy of <ds_source> to <ds_destination>
3805 */
3806
3807 708 static int recursive_copy(DYNAMIC_STRING *ds_source,
3808 DYNAMIC_STRING *ds_destination) {
3809 /* Note that my_dir sorts the list if not given any flags */
3810 MY_DIR *src_dir_info =
3811 708 my_dir(ds_source->str, MYF(MY_DONT_SORT | MY_WANT_STAT));
3812
3813 708 int error = 0;
3814
3815 /* Source directory exists */
3816
2/2
✓ Branch 0 taken 705 times.
✓ Branch 1 taken 3 times.
708 if (src_dir_info) {
3817 /* Note that my_dir sorts the list if not given any flags */
3818 MY_DIR *dest_dir_info =
3819
1/2
✓ Branch 0 taken 705 times.
✗ Branch 1 not taken.
705 my_dir(ds_destination->str, MYF(MY_DONT_SORT | MY_WANT_STAT));
3820
3821 /* Create destination directory if it doesn't exist */
3822
2/2
✓ Branch 0 taken 687 times.
✓ Branch 1 taken 18 times.
705 if (!dest_dir_info) {
3823
1/2
✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
687 error = my_mkdir(ds_destination->str, 0777, MYF(0)) != 0;
3824
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 684 times.
687 if (error) {
3825
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 my_dirend(dest_dir_info);
3826 3 goto end;
3827 }
3828 } else {
3829 /* Extracting the source directory name */
3830
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (ds_source->str[std::strlen(ds_source->str) - 1] == '/') {
3831 15 strmake(ds_source->str, ds_source->str,
3832
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 std::strlen(ds_source->str) - 1);
3833 15 ds_source->length = ds_source->length - 1;
3834 }
3835 18 char *src_dir_name = strrchr(ds_source->str, '/');
3836
3837 /* Extracting the destination directory name */
3838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (ds_destination->str[std::strlen(ds_destination->str) - 1] == '/') {
3839 strmake(ds_destination->str, ds_destination->str,
3840 std::strlen(ds_destination->str) - 1);
3841 ds_destination->length = ds_destination->length - 1;
3842 }
3843 18 char *dest_dir_name = strrchr(ds_destination->str, '/');
3844
3845 /*
3846 Destination directory might not exist if source directory
3847 name and destination directory name are not same.
3848
3849 For example, if source is "abc" and destintion is "def",
3850 check for the existence of directory "def/abc". If it exists
3851 then, copy the files from source directory(i.e "abc") to
3852 destination directory(i.e "def/abc"), otherwise create a new
3853 directory "abc" under "def" and copy the files from source to
3854 destination directory.
3855 */
3856
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (std::strcmp(src_dir_name, dest_dir_name)) {
3857
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 dynstr_append(ds_destination, src_dir_name);
3858
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 my_dirend(dest_dir_info);
3859 dest_dir_info =
3860
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 my_dir(ds_destination->str, MYF(MY_DONT_SORT | MY_WANT_STAT));
3861
3862 /* Create destination directory if it doesn't exist */
3863
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
15 if (!dest_dir_info) {
3864
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 error = my_mkdir(ds_destination->str, 0777, MYF(0)) != 0;
3865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (error) {
3866 my_dirend(dest_dir_info);
3867 goto end;
3868 }
3869 }
3870 }
3871 }
3872
3873 702 char dir_separator[2] = {FN_LIBCHAR, 0};
3874
1/2
✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
702 dynstr_append(ds_source, dir_separator);
3875
1/2
✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
702 dynstr_append(ds_destination, dir_separator);
3876
3877 /*
3878 Storing the length of source and destination
3879 directory paths so it can be reused.
3880 */
3881 702 size_t source_dir_length = ds_source->length;
3882 702 size_t destination_dir_length = ds_destination->length;
3883 ;
3884
3885
2/2
✓ Branch 0 taken 17478 times.
✓ Branch 1 taken 702 times.
18180 for (uint i = 0; i < src_dir_info->number_off_files; i++) {
3886 17478 ds_source->length = source_dir_length;
3887 17478 ds_destination->length = destination_dir_length;
3888 17478 FILEINFO *file = src_dir_info->dir_entry + i;
3889
3890 /* Skip the names "." and ".." */
3891
4/4
✓ Branch 0 taken 16776 times.
✓ Branch 1 taken 702 times.
✓ Branch 2 taken 702 times.
✓ Branch 3 taken 16074 times.
17478 if (!std::strcmp(file->name, ".") || !std::strcmp(file->name, ".."))
3892 1404 continue;
3893
3894
1/2
✓ Branch 0 taken 16074 times.
✗ Branch 1 not taken.
16074 dynstr_append(ds_source, file->name);
3895
1/2
✓ Branch 0 taken 16074 times.
✗ Branch 1 not taken.
16074 dynstr_append(ds_destination, file->name);
3896
3897
2/2
✓ Branch 0 taken 644 times.
✓ Branch 1 taken 15430 times.
16074 if (MY_S_ISDIR(file->mystat->st_mode))
3898
3/4
✓ Branch 0 taken 644 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 641 times.
✓ Branch 3 taken 3 times.
644 error = (recursive_copy(ds_source, ds_destination) != 0) ? 1 : error;
3899 else {
3900
3/8
✓ Branch 0 taken 15430 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15430 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15430 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
15430 DBUG_PRINT("info", ("Copying file: %s to %s", ds_source->str,
3901 ds_destination->str));
3902
3903 /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */
3904
1/2
✓ Branch 0 taken 15430 times.
✗ Branch 1 not taken.
30860 error = (my_copy(ds_source->str, ds_destination->str,
3905 MYF(MY_HOLD_ORIGINAL_MODES)) != 0)
3906
1/2
✓ Branch 0 taken 15430 times.
✗ Branch 1 not taken.
15430 ? 1
3907 : error;
3908 }
3909 }
3910
1/2
✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
702 my_dirend(dest_dir_info);
3911 }
3912 /* Source directory does not exist or access denied */
3913 else
3914 3 error = 1;
3915
3916 708 end:
3917 708 my_dirend(src_dir_info);
3918 708 return error;
3919 }
3920
3921 /*
3922 SYNOPSIS
3923 do_force_cpdir
3924 command - command handle
3925
3926 DESCRIPTION
3927 force-cpdir <from_directory> <to_directory>
3928 Recursive copy of <from_directory> to <to_directory>.
3929 Destination directory is created if it doesn't exist.
3930
3931 NOTE
3932 Will fail if <from_directory> doesn't exist.
3933 */
3934
3935 67 static void do_force_cpdir(struct st_command *command) {
3936
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 DBUG_TRACE;
3937
3938 static DYNAMIC_STRING ds_source;
3939 static DYNAMIC_STRING ds_destination;
3940
3941 67 const struct command_arg copy_file_args[] = {
3942 {"from_directory", ARG_STRING, true, &ds_source,
3943 "Directory to copy from"},
3944 {"to_directory", ARG_STRING, true, &ds_destination,
3945 "Directory to copy to"}};
3946
3947
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 check_command_args(command, command->first_argument, copy_file_args,
3948 sizeof(copy_file_args) / sizeof(struct command_arg), ' ');
3949
3950
3/8
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
67 DBUG_PRINT("info", ("Recursive copy files of %s to %s", ds_source.str,
3951 ds_destination.str));
3952
3953
3/8
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 67 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
67 DBUG_PRINT("info", ("listing directory: %s", ds_source.str));
3954
3955 67 int error = 0;
3956
3957 /*
3958 Throw an error if source directory path and
3959 destination directory path are same.
3960 */
3961
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 64 times.
67 if (!std::strcmp(ds_source.str, ds_destination.str)) {
3962 3 error = 1;
3963
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_my_errno(EEXIST);
3964 } else
3965
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 error = recursive_copy(&ds_source, &ds_destination);
3966
3967
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 handle_command_error(command, error);
3968
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 dynstr_free(&ds_source);
3969
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 dynstr_free(&ds_destination);
3970 67 }
3971
3972 /// Copy files from source directory to destination directory, by matching
3973 /// a specified file name pattern.
3974 ///
3975 /// Copy will fail if no files match the pattern. It will fail if source
3976 /// directory is empty and/or there are no files in it. Copy will also
3977 /// fail if source directory or destination directory or both do not
3978 /// exist. Retry of the command can happen optionally with an interval of
3979 /// one second between each retry if the command fails.
3980 ///
3981 /// @param command Pointer to the st_command structure which holds the
3982 /// arguments and information for the command.
3983 207 static void do_copy_files_wildcard(struct st_command *command) {
3984 static DYNAMIC_STRING ds_source;
3985 static DYNAMIC_STRING ds_destination;
3986 static DYNAMIC_STRING ds_wild;
3987 static DYNAMIC_STRING ds_retry;
3988
3989 207 const struct command_arg copy_file_args[] = {
3990 {"from_directory", ARG_STRING, true, &ds_source,
3991 "Directory to copy from"},
3992 {"to_directory", ARG_STRING, true, &ds_destination,
3993 "Directory to copy to"},
3994 {"pattern", ARG_STRING, true, &ds_wild, "File name pattern"},
3995 {"retry", ARG_STRING, false, &ds_retry, "Number of retries"}};
3996
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 DBUG_TRACE;
3997
3998
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
207 check_command_args(command, command->first_argument, copy_file_args,
3999 sizeof(copy_file_args) / sizeof(struct command_arg), ' ');
4000
4001
3/8
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 204 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
204 DBUG_PRINT("info",
4002 ("Copy files of %s to %s", ds_source.str, ds_destination.str));
4003
4004
3/8
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 204 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
204 DBUG_PRINT("info", ("listing directory: %s", ds_source.str));
4005
4006 204 int error = 0;
4007
4008 // Check if the retry value is passed, and if it is an integer
4009 204 int retry = 0;
4010
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 186 times.
204 if (ds_retry.length) {
4011
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 retry = get_int_val(ds_retry.str);
4012
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (retry < 0) {
4013 // In case of invalid retry, copy the value passed to print later
4014 char buf[32];
4015
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strmake(buf, ds_retry.str, sizeof(buf) - 1);
4016
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 free_dynamic_strings(&ds_source, &ds_destination, &ds_wild, &ds_retry);
4017 15 die("Invalid value '%s' for retry argument given to "
4018 "copy_files_wildcard command.",
4019 buf);
4020 }
4021 }
4022
4023 /* Note that my_dir sorts the list if not given any flags */
4024
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
189 MY_DIR *dir_info = my_dir(ds_source.str, MYF(MY_DONT_SORT | MY_WANT_STAT));
4025
4026 /* Directory does not exist or access denied */
4027
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 186 times.
189 if (!dir_info) {
4028 3 error = 1;
4029 3 goto end;
4030 }
4031
4032 /* The directory exists but is empty */
4033
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 183 times.
186 if (dir_info->number_off_files == 2) {
4034 3 error = 1;
4035
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_my_errno(ENOENT);
4036 3 goto end;
4037 }
4038
4039 char dir_separator[2];
4040 183 dir_separator[0] = FN_LIBCHAR;
4041 183 dir_separator[1] = 0;
4042
1/2
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
183 dynstr_append(&ds_source, dir_separator);
4043
1/2
✓ Branch 0 taken 183 times.
✗ Branch 1 not taken.
183 dynstr_append(&ds_destination, dir_separator);
4044
4045 /* Storing the length of the path to the file, so it can be reused */
4046 size_t source_file_length;
4047 size_t dest_file_length;
4048 183 dest_file_length = ds_destination.length;
4049 183 source_file_length = ds_source.length;
4050 uint match_count;
4051 183 match_count = 0;
4052
4053
2/2
✓ Branch 0 taken 8939 times.
✓ Branch 1 taken 180 times.
9119 for (uint i = 0; i < dir_info->number_off_files; i++) {
4054 8939 ds_source.length = source_file_length;
4055 8939 ds_destination.length = dest_file_length;
4056 8939 FILEINFO *file = dir_info->dir_entry + i;
4057
4058 /*
4059 Copy only regular files, i.e. no directories etc.
4060 if (!MY_S_ISREG(file->mystat->st_mode))
4061 MY_S_ISREG does not work here on Windows, just skip directories
4062 */
4063
2/2
✓ Branch 0 taken 930 times.
✓ Branch 1 taken 8009 times.
8939 if (MY_S_ISDIR(file->mystat->st_mode)) continue;
4064
4065 /* Copy only those files which the pattern matches */
4066
2/2
✓ Branch 0 taken 6561 times.
✓ Branch 1 taken 1448 times.
8009 if (wild_compare_full(file->name, std::strlen(file->name), ds_wild.str,
4067
1/2
✓ Branch 0 taken 8009 times.
✗ Branch 1 not taken.
8009 std::strlen(ds_wild.str), false, 0, '?', '*'))
4068 6561 continue;
4069
4070 1448 match_count++;
4071
1/2
✓ Branch 0 taken 1448 times.
✗ Branch 1 not taken.
1448 dynstr_append(&ds_source, file->name);
4072
1/2
✓ Branch 0 taken 1448 times.
✗ Branch 1 not taken.
1448 dynstr_append(&ds_destination, file->name);
4073
3/8
✓ Branch 0 taken 1448 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1448 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1448 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1448 DBUG_PRINT("info",
4074 ("Copying file: %s to %s", ds_source.str, ds_destination.str));
4075
4076 /* MY_HOLD_ORIGINAL_MODES prevents attempts to chown the file */
4077
1/2
✓ Branch 0 taken 1448 times.
✗ Branch 1 not taken.
1448 error = (my_copy(ds_source.str, ds_destination.str,
4078 1448 MYF(MY_HOLD_ORIGINAL_MODES)) != 0);
4079
4080 /*
4081 If the copy command fails due to an environmental issue, the command can
4082 be retried a specified number of times before throwing an error.
4083 */
4084
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1445 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
1448 for (int j = 0; error && (j < retry); j++) {
4085 my_sleep(1000 * 1000);
4086 error =
4087 (my_copy(ds_source.str, ds_destination.str,
4088 MYF(MY_DONT_OVERWRITE_FILE | MY_HOLD_ORIGINAL_MODES)) != 0);
4089 }
4090
4091
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1445 times.
1448 if (error) goto end;
4092 }
4093
4094 /* Pattern did not match any files */
4095
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 3 times.
180 if (!match_count) {
4096 3 error = 1;
4097
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 set_my_errno(ENOENT);
4098 }
4099
4100 177 end:
4101
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
189 my_dirend(dir_info);
4102
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
189 handle_command_error(command, error);
4103
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
189 free_dynamic_strings(&ds_source, &ds_destination, &ds_wild, &ds_retry);
4104 189 }
4105
4106 /*
4107 SYNOPSIS
4108 move_file_by_copy_delete
4109 from path of source
4110 to path of destination
4111
4112 DESCRIPTION
4113 Move <from_file> to <to_file>
4114 Auxiliary function for copying <from_file> to <to_file> followed by
4115 deleting <to_file>.
4116 */
4117
4118 static int move_file_by_copy_delete(const char *from, const char *to) {
4119 int error_copy, error_delete;
4120 error_copy = (my_copy(from, to, MYF(MY_HOLD_ORIGINAL_MODES)) != 0);
4121 if (error_copy) {
4122 return error_copy;
4123 }
4124
4125 error_delete = my_delete(from, MYF(0)) != 0;
4126
4127 /*
4128 If deleting the source file fails, rollback by deleting the
4129 redundant copy at the destinatiion.
4130 */
4131 if (error_delete) {
4132 my_delete(to, MYF(0));
4133 }
4134 return error_delete;
4135 }
4136
4137 /// Moves a file to destination file. Retry of the command can happen
4138 /// optionally with an interval of one second between each retry if
4139 /// the command fails.
4140 ///
4141 /// @param command Pointer to the st_command structure which holds the
4142 /// arguments and information for the command.
4143 274 static void do_move_file(struct st_command *command) {
4144 int error;
4145 static DYNAMIC_STRING ds_from_file;
4146 static DYNAMIC_STRING ds_to_file;
4147 static DYNAMIC_STRING ds_retry;
4148
4149 274 const struct command_arg move_file_args[] = {
4150 {"from_file", ARG_STRING, true, &ds_from_file, "Filename to move from"},
4151 {"to_file", ARG_STRING, true, &ds_to_file, "Filename to move to"},
4152 {"retry", ARG_STRING, false, &ds_retry, "Number of retries"}};
4153
1/2
✓ Branch 0 taken 274 times.
✗ Branch 1 not taken.
274 DBUG_TRACE;
4154
4155
1/2
✓ Branch 0 taken 268 times.
✗ Branch 1 not taken.
274 check_command_args(command, command->first_argument, move_file_args,
4156 sizeof(move_file_args) / sizeof(struct command_arg), ' ');
4157
4158 // Check if the retry value is passed, and if it is an integer
4159 268 int retry = 0;
4160
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 250 times.
268 if (ds_retry.length) {
4161
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 retry = get_int_val(ds_retry.str);
4162
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (retry < 0) {
4163 // In case of invalid retry, copy the value passed to print later
4164 char buf[32];
4165
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strmake(buf, ds_retry.str, sizeof(buf) - 1);
4166
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 free_dynamic_strings(&ds_from_file, &ds_to_file, &ds_retry);
4167 15 die("Invalid value '%s' for retry argument given to move_file "
4168 "command.",
4169 buf);
4170 }
4171 }
4172
4173
3/8
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 253 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 253 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
253 DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str));
4174
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 error = (my_rename(ds_from_file.str, ds_to_file.str, MYF(0)) != 0);
4175
4176 /*
4177 Use my_copy() followed by my_delete() for moving a file instead of
4178 my_rename() when my_errno is EXDEV. This is because my_rename() fails
4179 with the error "Invalid cross-device link" while moving a file between
4180 locations having different filesystems in some operating systems.
4181 */
4182
5/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 250 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 253 times.
253 if (error && (my_errno() == EXDEV)) {
4183 error = move_file_by_copy_delete(ds_from_file.str, ds_to_file.str);
4184 }
4185
4186 /*
4187 If the command fails due to an environmental issue, the command can be
4188 retried a specified number of times before throwing an error.
4189 */
4190
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 250 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
253 for (int i = 0; error && (i < retry); i++) {
4191 my_sleep(1000 * 1000);
4192 error = (my_rename(ds_from_file.str, ds_to_file.str, MYF(0)) != 0);
4193
4194 if (error && (my_errno() == EXDEV))
4195 error = move_file_by_copy_delete(ds_from_file.str, ds_to_file.str);
4196 }
4197
4198
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 handle_command_error(command, error);
4199
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
253 free_dynamic_strings(&ds_from_file, &ds_to_file, &ds_retry);
4200 253 }
4201
4202 /*
4203 SYNOPSIS
4204 do_chmod_file
4205 command command handle
4206
4207 DESCRIPTION
4208 chmod <octal> <file_name>
4209 Change file permission of <file_name>
4210
4211 */
4212
4213 349 static void do_chmod_file(struct st_command *command) {
4214 349 long mode = 0;
4215 int err_code;
4216 static DYNAMIC_STRING ds_mode;
4217 static DYNAMIC_STRING ds_file;
4218 349 const struct command_arg chmod_file_args[] = {
4219 {"mode", ARG_STRING, true, &ds_mode, "Mode of file(octal) ex. 0660"},
4220 {"filename", ARG_STRING, true, &ds_file, "Filename of file to modify"}};
4221
1/2
✓ Branch 0 taken 349 times.
✗ Branch 1 not taken.
349 DBUG_TRACE;
4222
4223
1/2
✓ Branch 0 taken 343 times.
✗ Branch 1 not taken.
349 check_command_args(command, command->first_argument, chmod_file_args,
4224 sizeof(chmod_file_args) / sizeof(struct command_arg), ' ');
4225
4226 /* Parse what mode to set */
4227
4/4
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 331 times.
677 if (ds_mode.length != 4 ||
4228
3/4
✓ Branch 0 taken 334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 331 times.
334 str2int(ds_mode.str, 8, 0, INT_MAX, &mode) == NullS)
4229 12 die("You must write a 4 digit octal number for mode");
4230
4231
3/8
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 331 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 331 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
331 DBUG_PRINT("info", ("chmod %o %s", (uint)mode, ds_file.str));
4232 331 err_code = chmod(ds_file.str, mode);
4233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 331 times.
331 if (err_code < 0) err_code = 1;
4234
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 handle_command_error(command, err_code);
4235
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 dynstr_free(&ds_mode);
4236
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 dynstr_free(&ds_file);
4237 331 }
4238
4239 /// Check if specified file exists. Retry of the command can happen
4240 /// optionally with an interval of one second between each retry if
4241 /// the command fails.
4242 ///
4243 /// @param command Pointer to the st_command structure which holds the
4244 /// arguments and information for the command.
4245 714 static void do_file_exist(struct st_command *command) {
4246 int error;
4247 static DYNAMIC_STRING ds_filename;
4248 static DYNAMIC_STRING ds_retry;
4249
4250 714 const struct command_arg file_exist_args[] = {
4251 {"filename", ARG_STRING, true, &ds_filename, "File to check if it exist"},
4252 {"retry", ARG_STRING, false, &ds_retry, "Number of retries"}};
4253
1/2
✓ Branch 0 taken 714 times.
✗ Branch 1 not taken.
714 DBUG_TRACE;
4254
4255
1/2
✓ Branch 0 taken 711 times.
✗ Branch 1 not taken.
714 check_command_args(command, command->first_argument, file_exist_args,
4256 sizeof(file_exist_args) / sizeof(struct command_arg), ' ');
4257
4258 // Check if the retry value is passed, and if it is an integer
4259 711 int retry = 0;
4260
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 693 times.
711 if (ds_retry.length) {
4261
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 retry = get_int_val(ds_retry.str);
4262
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 if (retry < 0) {
4263 // In case of invalid retry, copy the value passed to print later
4264 char buf[32];
4265
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 strmake(buf, ds_retry.str, sizeof(buf) - 1);
4266
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 free_dynamic_strings(&ds_filename, &ds_retry);
4267 15 die("Invalid value '%s' for retry argument given to file_exists "
4268 "command.",
4269 buf);
4270 }
4271 }
4272
4273
3/8
✓ Branch 0 taken 696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 696 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 696 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
696 DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str));
4274 696 error = (access(ds_filename.str, F_OK) != 0);
4275
4276 /*
4277 If the file_exists command fails due to an environmental issue, the command
4278 can be retried a specified number of times before throwing an error.
4279 */
4280
3/4
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 565 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 131 times.
696 for (int i = 0; error && (i < retry); i++) {
4281 my_sleep(1000 * 1000);
4282 error = (access(ds_filename.str, F_OK) != 0);
4283 }
4284
4285
1/2
✓ Branch 0 taken 696 times.
✗ Branch 1 not taken.
696 handle_command_error(command, error);
4286
1/2
✓ Branch 0 taken 696 times.
✗ Branch 1 not taken.
696 free_dynamic_strings(&ds_filename, &ds_retry);
4287 696 }
4288
4289 /*
4290 SYNOPSIS
4291 do_mkdir
4292 command called command
4293
4294 DESCRIPTION
4295 mkdir <dir_name>
4296 Create the directory <dir_name>
4297 */
4298
4299 366 static void do_mkdir(struct st_command *command) {
4300 int error;
4301 static DYNAMIC_STRING ds_dirname;
4302 366 const struct command_arg mkdir_args[] = {
4303 {"dirname", ARG_STRING, true, &ds_dirname, "Directory to create"}};
4304
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 DBUG_TRACE;
4305
4306
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 check_command_args(command, command->first_argument, mkdir_args,
4307 sizeof(mkdir_args) / sizeof(struct command_arg), ' ');
4308
4309
3/8
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 366 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 366 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
366 DBUG_PRINT("info", ("creating directory: %s", ds_dirname.str));
4310
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 error = my_mkdir(ds_dirname.str, 0777, MYF(0)) != 0;
4311
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 handle_command_error(command, error);
4312
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 dynstr_free(&ds_dirname);
4313 366 }
4314
4315 /*
4316 SYNOPSIS
4317 do_force_rmdir
4318 command - command handle
4319 ds_dirname - pointer to dynamic string containing directory information
4320
4321 DESCRIPTION
4322 force-rmdir <dir_name>
4323 Remove the directory <dir_name>
4324 */
4325
4326 4661 void do_force_rmdir(struct st_command *command, DYNAMIC_STRING *ds_dirname) {
4327
1/2
✓ Branch 0 taken 4661 times.
✗ Branch 1 not taken.
4661 DBUG_TRACE;
4328
4329 char dir_name[FN_REFLEN + 1];
4330 4661 strncpy(dir_name, ds_dirname->str, sizeof(dir_name) - 1);
4331 4661 dir_name[FN_REFLEN] = '\0';
4332
4333 /* Note that my_dir sorts the list if not given any flags */
4334
1/2
✓ Branch 0 taken 4661 times.
✗ Branch 1 not taken.
4661 MY_DIR *dir_info = my_dir(ds_dirname->str, MYF(MY_DONT_SORT | MY_WANT_STAT));
4335
4336
4/4
✓ Branch 0 taken 4628 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 3948 times.
✓ Branch 3 taken 680 times.
4661 if (dir_info && dir_info->number_off_files > 2) {
4337 /* Storing the length of the path to the file, so it can be reused */
4338 3948 size_t length = ds_dirname->length;
4339
4340 /* Delete the directory recursively */
4341
2/2
✓ Branch 0 taken 89855 times.
✓ Branch 1 taken 3948 times.
93803 for (uint i = 0; i < dir_info->number_off_files; i++) {
4342 89855 FILEINFO *file = dir_info->dir_entry + i;
4343
4344 /* Skip the names "." and ".." */
4345
4/4
✓ Branch 0 taken 85907 times.
✓ Branch 1 taken 3948 times.
✓ Branch 2 taken 3948 times.
✓ Branch 3 taken 81959 times.
89855 if (!std::strcmp(file->name, ".") || !std::strcmp(file->name, ".."))
4346 7896 continue;
4347
4348 81959 ds_dirname->length = length;
4349 81959 char dir_separator[2] = {FN_LIBCHAR, 0};
4350
1/2
✓ Branch 0 taken 81959 times.
✗ Branch 1 not taken.
81959 dynstr_append(ds_dirname, dir_separator);
4351
1/2
✓ Branch 0 taken 81959 times.
✗ Branch 1 not taken.
81959 dynstr_append(ds_dirname, file->name);
4352
4353
2/2
✓ Branch 0 taken 3945 times.
✓ Branch 1 taken 78014 times.
81959 if (MY_S_ISDIR(file->mystat->st_mode)) /* It's a directory */
4354
1/2
✓ Branch 0 taken 3945 times.
✗ Branch 1 not taken.
3945 do_force_rmdir(command, ds_dirname);
4355 else
4356 /* It's a file */
4357
1/2
✓ Branch 0 taken 78014 times.
✗ Branch 1 not taken.
78014 my_delete(ds_dirname->str, MYF(0));
4358 }
4359 }
4360
4361
1/2
✓ Branch 0 taken 4661 times.
✗ Branch 1 not taken.
4661 my_dirend(dir_info);
4362 4661 int error = rmdir(dir_name) != 0;
4363
1/2
✓ Branch 0 taken 4661 times.
✗ Branch 1 not taken.
4661 set_my_errno(errno);
4364
1/2
✓ Branch 0 taken 4661 times.
✗ Branch 1 not taken.
4661 handle_command_error(command, error);
4365 4661 }
4366
4367 /*
4368 SYNOPSIS
4369 do_rmdir
4370 command called command
4371 force Recursively delete a directory if the value is set to true,
4372 otherwise delete an empty directory
4373
4374 DESCRIPTION
4375 rmdir <dir_name>
4376 Remove the empty directory <dir_name>
4377 */
4378
4379 956 static void do_rmdir(struct st_command *command, bool force) {
4380 int error;
4381 static DYNAMIC_STRING ds_dirname;
4382 956 const struct command_arg rmdir_args[] = {
4383 {"dirname", ARG_STRING, true, &ds_dirname, "Directory to remove"}};
4384
1/2
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
956 DBUG_TRACE;
4385
4386
1/2
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
956 check_command_args(command, command->first_argument, rmdir_args,
4387 sizeof(rmdir_args) / sizeof(struct command_arg), ' ');
4388
4389
3/8
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 956 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 956 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
956 DBUG_PRINT("info", ("removing directory: %s", ds_dirname.str));
4390
2/2
✓ Branch 0 taken 716 times.
✓ Branch 1 taken 240 times.
956 if (force)
4391
1/2
✓ Branch 0 taken 716 times.
✗ Branch 1 not taken.
716 do_force_rmdir(command, &ds_dirname);
4392 else {
4393 240 error = rmdir(ds_dirname.str) != 0;
4394
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 set_my_errno(errno);
4395
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 handle_command_error(command, error);
4396 }
4397
1/2
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
956 dynstr_free(&ds_dirname);
4398 956 }
4399
4400 /*
4401 SYNOPSIS
4402 get_list_files
4403 ds output
4404 ds_dirname dir to list
4405 ds_wild wild-card file pattern (can be empty)
4406
4407 DESCRIPTION
4408 list all entries in directory (matching ds_wild if given)
4409 */
4410
4411 132778 static int get_list_files(DYNAMIC_STRING *ds, const DYNAMIC_STRING *ds_dirname,
4412 const DYNAMIC_STRING *ds_wild) {
4413 uint i;
4414 MY_DIR *dir_info;
4415 FILEINFO *file;
4416
1/2
✓ Branch 0 taken 132778 times.
✗ Branch 1 not taken.
132778 DBUG_TRACE;
4417
4418
3/8
✓ Branch 0 taken 132778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 132778 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 132778 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
132778 DBUG_PRINT("info", ("listing directory: %s", ds_dirname->str));
4419 /* Note that my_dir sorts the list if not given any flags */
4420
2/4
✓ Branch 0 taken 132778 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 132778 times.
132778 if (!(dir_info = my_dir(ds_dirname->str, MYF(0)))) return 1;
4421
2/2
✓ Branch 0 taken 7933484 times.
✓ Branch 1 taken 132778 times.
8066262 for (i = 0; i < (uint)dir_info->number_off_files; i++) {
4422 7933484 file = dir_info->dir_entry + i;
4423
2/2
✓ Branch 0 taken 291895 times.
✓ Branch 1 taken 7641589 times.
7933484 if (file->name[0] == '.' &&
4424
2/2
✓ Branch 0 taken 159117 times.
✓ Branch 1 taken 132778 times.
291895 (file->name[1] == '\0' ||
4425
3/4
✓ Branch 0 taken 132778 times.
✓ Branch 1 taken 26339 times.
✓ Branch 2 taken 132778 times.
✗ Branch 3 not taken.
159117 (file->name[1] == '.' && file->name[2] == '\0')))
4426 265556 continue; /* . or .. */
4427
5/6
✓ Branch 0 taken 7667928 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7663814 times.
✓ Branch 3 taken 4114 times.
✓ Branch 4 taken 2339 times.
✓ Branch 5 taken 7665589 times.
15331742 if (ds_wild && ds_wild->length &&
4428
2/2
✓ Branch 0 taken 2339 times.
✓ Branch 1 taken 7661475 times.
7663814 wild_compare_full(file->name, std::strlen(file->name), ds_wild->str,
4429
1/2
✓ Branch 0 taken 7663814 times.
✗ Branch 1 not taken.
7663814 std::strlen(ds_wild->str), false, 0, '?', '*'))
4430 2339 continue;
4431
1/2
✓ Branch 0 taken 7665589 times.
✗ Branch 1 not taken.
7665589 replace_dynstr_append(ds, file->name);
4432
1/2
✓ Branch 0 taken 7665589 times.
✗ Branch 1 not taken.
7665589 dynstr_append(ds, "\n");
4433 }
4434
1/2
✓ Branch 0 taken 132778 times.
✗ Branch 1 not taken.
132778 my_dirend(dir_info);
4435 132778 return 0;
4436 132778 }
4437
4438 /*
4439 SYNOPSIS
4440 do_list_files
4441 command called command
4442
4443 DESCRIPTION
4444 list_files <dir_name> [<file_name>]
4445 List files and directories in directory <dir_name> (like `ls`)
4446 [Matching <file_name>, where wild-cards are allowed]
4447 */
4448
4449 773 static void do_list_files(struct st_command *command) {
4450 int error;
4451 static DYNAMIC_STRING ds_dirname;
4452 static DYNAMIC_STRING ds_wild;
4453 773 const struct command_arg list_files_args[] = {
4454 {"dirname", ARG_STRING, true, &ds_dirname, "Directory to list"},
4455 {"file", ARG_STRING, false, &ds_wild, "Filename (incl. wildcard)"}};
4456
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 DBUG_TRACE;
4457 773 command->used_replace = true;
4458
4459
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 check_command_args(command, command->first_argument, list_files_args,
4460 sizeof(list_files_args) / sizeof(struct command_arg), ' ');
4461
4462
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 error = get_list_files(&ds_res, &ds_dirname, &ds_wild);
4463
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 handle_command_error(command, error);
4464
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 dynstr_free(&ds_dirname);
4465
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 dynstr_free(&ds_wild);
4466 773 }
4467
4468 /*
4469 SYNOPSIS
4470 do_list_files_write_file_command
4471 command called command
4472 append append file, or create new
4473
4474 DESCRIPTION
4475 list_files_{write|append}_file <filename> <dir_name> [<match_file>]
4476 List files and directories in directory <dir_name> (like `ls`)
4477 [Matching <match_file>, where wild-cards are allowed]
4478
4479 Note: File will be truncated if exists and append is not true.
4480 */
4481
4482 132005 static void do_list_files_write_file_command(struct st_command *command,
4483 bool append) {
4484 int error;
4485 static DYNAMIC_STRING ds_content;
4486 static DYNAMIC_STRING ds_filename;
4487 static DYNAMIC_STRING ds_dirname;
4488 static DYNAMIC_STRING ds_wild;
4489 132005 const struct command_arg list_files_args[] = {
4490 {"filename", ARG_STRING, true, &ds_filename, "Filename for write"},
4491 {"dirname", ARG_STRING, true, &ds_dirname, "Directory to list"},
4492 {"file", ARG_STRING, false, &ds_wild, "Filename (incl. wildcard)"}};
4493
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 DBUG_TRACE;
4494 132005 command->used_replace = true;
4495
4496
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 check_command_args(command, command->first_argument, list_files_args,
4497 sizeof(list_files_args) / sizeof(struct command_arg), ' ');
4498
4499
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 init_dynamic_string(&ds_content, "", 1024);
4500
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 error = get_list_files(&ds_content, &ds_dirname, &ds_wild);
4501
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 handle_command_error(command, error);
4502
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append);
4503
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 dynstr_free(&ds_content);
4504
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 dynstr_free(&ds_filename);
4505
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 dynstr_free(&ds_dirname);
4506
1/2
✓ Branch 0 taken 132005 times.
✗ Branch 1 not taken.
132005 dynstr_free(&ds_wild);
4507 132005 }
4508
4509 /*
4510 Read characters from line buffer or file. This is needed to allow
4511 my_ungetc() to buffer MAX_DELIMITER_LENGTH characters for a file
4512
4513 NOTE:
4514 This works as long as one doesn't change files (with 'source file_name')
4515 when there is things pushed into the buffer. This should however not
4516 happen for any tests in the test suite.
4517 */
4518
4519 15199513967 static int my_getc(FILE *file) {
4520
2/2
✓ Branch 0 taken 15195281861 times.
✓ Branch 1 taken 4232106 times.
15199513967 if (line_buffer_pos == line_buffer) return fgetc(file);
4521 4232106 return *--line_buffer_pos;
4522 }
4523
4524 4232106 static void my_ungetc(int c) { *line_buffer_pos++ = (char)c; }
4525
4526 463337 static void read_until_delimiter(DYNAMIC_STRING *ds,
4527 DYNAMIC_STRING *ds_delimiter) {
4528 char c;
4529
1/2
✓ Branch 0 taken 463337 times.
✗ Branch 1 not taken.
463337 DBUG_TRACE;
4530
3/8
✓ Branch 0 taken 463337 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 463337 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 463337 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
463337 DBUG_PRINT("enter", ("delimiter: %s, length: %u", ds_delimiter->str,
4531 (uint)ds_delimiter->length));
4532
4533
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 463334 times.
463337 if (ds_delimiter->length > MAX_DELIMITER_LENGTH)
4534 3 die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH);
4535
4536 /* Read from file until delimiter is found */
4537 while (true) {
4538
1/2
✓ Branch 0 taken 202910340 times.
✗ Branch 1 not taken.
202910340 c = my_getc(cur_file->file);
4539
4540
2/2
✓ Branch 0 taken 6412406 times.
✓ Branch 1 taken 196497934 times.
202910340 if (c == '\n') {
4541 6412406 cur_file->lineno++;
4542
4543 /* Skip newline from the same line as the command */
4544
2/2
✓ Branch 0 taken 259458 times.
✓ Branch 1 taken 6152948 times.
6412406 if (start_lineno == (cur_file->lineno - 1)) continue;
4545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196497934 times.
196497934 } else if (start_lineno == cur_file->lineno) {
4546 /*
4547 No characters except \n are allowed on
4548 the same line as the command
4549 */
4550 die("Trailing characters found after command");
4551 }
4552
4553
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 202650879 times.
202650882 if (feof(cur_file->file))
4554 3 die("End of file encountered before '%s' delimiter was found",
4555 ds_delimiter->str);
4556
4557
3/4
✓ Branch 0 taken 202650879 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 463331 times.
✓ Branch 3 taken 202187548 times.
202650879 if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length)) {
4558
3/8
✓ Branch 0 taken 463331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 463331 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 463331 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
463331 DBUG_PRINT("exit", ("Found delimiter '%s'", ds_delimiter->str));
4559 463331 break;
4560 }
4561
1/2
✓ Branch 0 taken 202187548 times.
✗ Branch 1 not taken.
202187548 dynstr_append_mem(ds, (const char *)&c, 1);
4562 }
4563
3/8
✓ Branch 0 taken 463331 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 463331 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 463331 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
463331 DBUG_PRINT("exit", ("ds: %s", ds->str));
4564 463331 }
4565
4566 171642 static void do_write_file_command(struct st_command *command, bool append) {
4567 static DYNAMIC_STRING ds_content;
4568 static DYNAMIC_STRING ds_filename;
4569 static DYNAMIC_STRING ds_delimiter;
4570 171642 const struct command_arg write_file_args[] = {
4571 {"filename", ARG_STRING, true, &ds_filename, "File to write to"},
4572 {"delimiter", ARG_STRING, false, &ds_delimiter,
4573 "Delimiter to read until"}};
4574
1/2
✓ Branch 0 taken 171642 times.
✗ Branch 1 not taken.
171642 DBUG_TRACE;
4575
4576
1/2
✓ Branch 0 taken 171639 times.
✗ Branch 1 not taken.
171642 check_command_args(command, command->first_argument, write_file_args,
4577 sizeof(write_file_args) / sizeof(struct command_arg), ' ');
4578
4579
6/6
✓ Branch 0 taken 27658 times.
✓ Branch 1 taken 143981 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 27655 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 171636 times.
171639 if (!append && access(ds_filename.str, F_OK) == 0) {
4580 /* The file should not be overwritten */
4581 3 die("File already exist: '%s'", ds_filename.str);
4582 }
4583
4584 171636 ds_content = command->content;
4585 /* If it hasn't been done already by a loop iteration, fill it in */
4586
2/2
✓ Branch 0 taken 165574 times.
✓ Branch 1 taken 6062 times.
171636 if (!ds_content.str) {
4587 /* If no delimiter was provided, use EOF */
4588
3/4
✓ Branch 0 taken 165416 times.
✓ Branch 1 taken 158 times.
✓ Branch 2 taken 165416 times.
✗ Branch 3 not taken.
165574 if (ds_delimiter.length == 0) dynstr_set(&ds_delimiter, "EOF");
4589
4590
1/2
✓ Branch 0 taken 165574 times.
✗ Branch 1 not taken.
165574 init_dynamic_string(&ds_content, "", 1024);
4591
1/2
✓ Branch 0 taken 165571 times.
✗ Branch 1 not taken.
165574 read_until_delimiter(&ds_content, &ds_delimiter);
4592 165571 command->content = ds_content;
4593 }
4594 /* This function could be called even if "false", so check before printing */
4595
2/2
✓ Branch 0 taken 162323 times.
✓ Branch 1 taken 9310 times.
171633 if (cur_block->ok) {
4596
3/8
✓ Branch 0 taken 162323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 162323 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 162323 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
162323 DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str));
4597
1/2
✓ Branch 0 taken 162323 times.
✗ Branch 1 not taken.
162323 str_to_file2(ds_filename.str, ds_content.str, ds_content.length, append);
4598 }
4599
1/2
✓ Branch 0 taken 171633 times.
✗ Branch 1 not taken.
171633 dynstr_free(&ds_filename);
4600
1/2
✓ Branch 0 taken 171633 times.
✗ Branch 1 not taken.
171633 dynstr_free(&ds_delimiter);
4601 171633 }
4602
4603 /*
4604 SYNOPSIS
4605 do_write_file
4606 command called command
4607
4608 DESCRIPTION
4609 write_file <file_name> [<delimiter>];
4610 <what to write line 1>
4611 <...>
4612 < what to write line n>
4613 EOF
4614
4615 --write_file <file_name>;
4616 <what to write line 1>
4617 <...>
4618 < what to write line n>
4619 EOF
4620
4621 Write everything between the "write_file" command and 'delimiter'
4622 to "file_name"
4623
4624 NOTE! Will fail if <file_name> exists
4625
4626 Default <delimiter> is EOF
4627
4628 */
4629
4630 27661 static void do_write_file(struct st_command *command) {
4631 27661 do_write_file_command(command, false);
4632 27652 }
4633
4634 /*
4635 SYNOPSIS
4636 do_append_file
4637 command called command
4638
4639 DESCRIPTION
4640 append_file <file_name> [<delimiter>];
4641 <what to write line 1>
4642 <...>
4643 < what to write line n>
4644 EOF
4645
4646 --append_file <file_name>;
4647 <what to write line 1>
4648 <...>
4649 < what to write line n>
4650 EOF
4651
4652 Append everything between the "append_file" command
4653 and 'delimiter' to "file_name"
4654
4655 Default <delimiter> is EOF
4656
4657 */
4658
4659 143981 static void do_append_file(struct st_command *command) {
4660 143981 do_write_file_command(command, true);
4661 143981 }
4662
4663 /*
4664 SYNOPSIS
4665 do_cat_file
4666 command called command
4667
4668 DESCRIPTION
4669 cat_file <file_name>;
4670
4671 Print the given file to result log
4672
4673 */
4674
4675 13147 static void do_cat_file(struct st_command *command) {
4676 int error;
4677 static DYNAMIC_STRING ds_filename;
4678 13147 const struct command_arg cat_file_args[] = {
4679 {"filename", ARG_STRING, true, &ds_filename, "File to read from"}};
4680
1/2
✓ Branch 0 taken 13147 times.
✗ Branch 1 not taken.
13147 DBUG_TRACE;
4681 13147 command->used_replace = true;
4682
4683
1/2
✓ Branch 0 taken 13147 times.
✗ Branch 1 not taken.
13147 check_command_args(command, command->first_argument, cat_file_args,
4684 sizeof(cat_file_args) / sizeof(struct command_arg), ' ');
4685
4686
3/8
✓ Branch 0 taken 13147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13147 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 13147 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
13147 DBUG_PRINT("info", ("Reading from, file: %s", ds_filename.str));
4687
4688
1/2
✓ Branch 0 taken 13147 times.
✗ Branch 1 not taken.
13147 error = cat_file(&ds_res, ds_filename.str);
4689
1/2
✓ Branch 0 taken 13144 times.
✗ Branch 1 not taken.
13147 handle_command_error(command, error);
4690
1/2
✓ Branch 0 taken 13144 times.
✗ Branch 1 not taken.
13144 dynstr_free(&ds_filename);
4691 13144 }
4692
4693 /// Compare the two files.
4694 ///
4695 /// Success if 2 files are same, failure if the files are different or
4696 /// either file does not exist.
4697 ///
4698 /// @code
4699 /// diff_files <file1> <file2>;
4700 /// @endcode
4701 ///
4702 /// @param command Pointer to the st_command structure which holds the
4703 /// arguments and information for the command.
4704 9176 static void do_diff_files(struct st_command *command) {
4705 static DYNAMIC_STRING ds_filename1;
4706 static DYNAMIC_STRING ds_filename2;
4707
4708 9176 const struct command_arg diff_file_args[] = {
4709 {"file1", ARG_STRING, true, &ds_filename1, "First file to diff"},
4710 {"file2", ARG_STRING, true, &ds_filename2, "Second file to diff"}};
4711
4712
1/2
✓ Branch 0 taken 9176 times.
✗ Branch 1 not taken.
9176 check_command_args(command, command->first_argument, diff_file_args,
4713 sizeof(diff_file_args) / sizeof(struct command_arg), ' ');
4714
4715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9176 times.
9176 if (access(ds_filename1.str, F_OK) != 0)
4716 die("Command \"diff_files\" failed, file '%s' does not exist.",
4717 ds_filename1.str);
4718
4719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9176 times.
9176 if (access(ds_filename2.str, F_OK) != 0)
4720 die("Command \"diff_files\" failed, file '%s' does not exist.",
4721 ds_filename2.str);
4722
4723 9176 int error = 0;
4724
4/6
✓ Branch 0 taken 9176 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 9164 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9176 times.
9188 if ((error = compare_files(ds_filename1.str, ds_filename2.str)) &&
4725
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 match_expected_error(command, error, nullptr) < 0) {
4726 // Compare of the two files failed, append them to output so the
4727 // failure can be analyzed, but only if it was not expected to fail.
4728 show_diff(&ds_res, ds_filename1.str, ds_filename2.str);
4729 if (log_file.write(ds_res.str, ds_res.length) || log_file.flush())
4730 cleanup_and_exit(1);
4731 dynstr_set(&ds_res, nullptr);
4732 }
4733
4734
1/2
✓ Branch 0 taken 9176 times.
✗ Branch 1 not taken.
9176 free_dynamic_strings(&ds_filename1, &ds_filename2);
4735
1/2
✓ Branch 0 taken 9176 times.
✗ Branch 1 not taken.
9176 handle_command_error(command, error);
4736 9176 }
4737
4738 1109476 static struct st_connection *find_connection_by_name(const char *name) {
4739 struct st_connection *con;
4740
2/2
✓ Branch 0 taken 16238024 times.
✓ Branch 1 taken 46243 times.
16284267 for (con = connections; con < next_con; con++) {
4741
2/2
✓ Branch 0 taken 1063233 times.
✓ Branch 1 taken 15174791 times.
16238024 if (!std::strcmp(con->name, name)) {
4742 1063233 return con;
4743 }
4744 }
4745 46243 return nullptr; /* Connection not found */
4746 }
4747
4748 /*
4749 SYNOPSIS
4750 do_send_quit
4751 command called command
4752
4753 DESCRIPTION
4754 Sends a simple quit command to the server for the named connection.
4755
4756 */
4757
4758 2000 static void do_send_quit(struct st_command *command) {
4759 2000 char *p = command->first_argument;
4760 const char *name;
4761 struct st_connection *con;
4762
4763
1/2
✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
2000 DBUG_TRACE;
4764
3/8
✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2000 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2000 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2000 DBUG_PRINT("enter", ("name: '%s'", p));
4765
4766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2000 times.
2000 if (!*p) die("Missing connection name in send_quit");
4767 2000 name = p;
4768
3/4
✓ Branch 0 taken 14000 times.
✓ Branch 1 taken 2000 times.
✓ Branch 2 taken 14000 times.
✗ Branch 3 not taken.
16000 while (*p && !my_isspace(charset_info, *p)) p++;
4769
4770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2000 times.
2000 if (*p) *p++ = 0;
4771 2000 command->last_argument = p;
4772
4773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2000 times.
2000 if (!(con = find_connection_by_name(name)))
4774 die("connection '%s' not found in connection pool", name);
4775
4776
2/6
✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2000 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2000 simple_command(&con->mysql, COM_QUIT, nullptr, 0, 1);
4777 2000 }
4778
4779 /*
4780 SYNOPSIS
4781 do_change_user
4782 command called command
4783
4784 DESCRIPTION
4785 change_user [<user>], [<passwd>], [<db>]
4786 <user> - user to change to
4787 <passwd> - user password
4788 <db> - default database
4789
4790 Changes the user and causes the database specified by db to become
4791 the default (current) database for the the current connection.
4792
4793 */
4794
4795 109 static void do_change_user(struct st_command *command) {
4796 109 MYSQL *mysql = &cur_con->mysql;
4797 static DYNAMIC_STRING ds_user, ds_passwd, ds_db, ds_reconnect;
4798 109 bool reconnect = true;
4799 109 const struct command_arg change_user_args[] = {
4800 {"user", ARG_STRING, false, &ds_user, "User to connect as"},
4801 {"password", ARG_STRING, false, &ds_passwd,
4802 "Password used when connecting"},
4803 {"database", ARG_STRING, false, &ds_db,
4804 "Database to select after connect"},
4805 {"reconnect", ARG_STRING, false, &ds_reconnect, "Reconnect on fail"},
4806 };
4807 109 const char *reconnect_on_fail = "reconnect_on_fail";
4808 109 const char *do_not_reconnect_on_fail = "do_not_reconnect_on_fail";
4809
4810
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 DBUG_TRACE;
4811
4812
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 check_command_args(command, command->first_argument, change_user_args,
4813 sizeof(change_user_args) / sizeof(struct command_arg),
4814 ',');
4815
4816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
109 if (cur_con->stmt) {
4817 mysql_stmt_close(cur_con->stmt);
4818 cur_con->stmt = nullptr;
4819 }
4820
4821
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 89 times.
109 if (!ds_user.length) {
4822
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 dynstr_set(&ds_user, mysql->user);
4823
4824
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (!ds_passwd.length) dynstr_set(&ds_passwd, mysql->passwd);
4825
4826
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
20 if (!ds_db.length) dynstr_set(&ds_db, mysql->db);
4827 }
4828
4829
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 108 times.
109 if (ds_reconnect.length != 0) {
4830
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (strcmp(ds_reconnect.str, do_not_reconnect_on_fail) == 0)
4831 1 reconnect = false;
4832 else if (strcmp(ds_reconnect.str, reconnect_on_fail) == 0)
4833 reconnect = true;
4834 else
4835 die("Wrong value specified for 'reconnect' parameter. "
4836 "Allowed value are '%s' and '%s'",
4837 do_not_reconnect_on_fail, reconnect_on_fail);
4838 }
4839
4840
3/10
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 109 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 109 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
109 DBUG_PRINT("info", ("connection: '%s' user: '%s' password: '%s' "
4841 "database: '%s' reconnect: '%s'",
4842 cur_con->name, ds_user.str, ds_passwd.str, ds_db.str,
4843 reconnect ? "true" : "false"));
4844
4845
3/4
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 80 times.
109 if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str)) {
4846
4/8
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 29 times.
✗ Branch 7 not taken.
29 handle_error(curr_command, mysql_errno(mysql), mysql_error(mysql),
4847 mysql_sqlstate(mysql), &ds_res);
4848
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 1 times.
29 if (reconnect) {
4849 28 mysql->reconnect = true;
4850
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 mysql_reconnect(&cur_con->mysql);
4851 }
4852 } else
4853
1/2
✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
80 handle_no_error(command);
4854
4855
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 dynstr_free(&ds_user);
4856
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 dynstr_free(&ds_passwd);
4857
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 dynstr_free(&ds_db);
4858
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 dynstr_free(&ds_reconnect);
4859 109 }
4860
4861 /*
4862 SYNOPSIS
4863 do_perl
4864 command command handle
4865
4866 DESCRIPTION
4867 perl [<delimiter>];
4868 <perlscript line 1>
4869 <...>
4870 <perlscript line n>
4871 EOF
4872
4873 Execute everything after "perl" until <delimiter> as perl.
4874 Useful for doing more advanced things
4875 but still being able to execute it on all platforms.
4876
4877 Default <delimiter> is EOF
4878 */
4879
4880 1389021 static void do_perl(struct st_command *command) {
4881 int error;
4882 File fd;
4883 FILE *res_file;
4884 char buf[FN_REFLEN + 10];
4885 char temp_file_path[FN_REFLEN];
4886 static DYNAMIC_STRING ds_script;
4887 static DYNAMIC_STRING ds_delimiter;
4888 1389021 const struct command_arg perl_args[] = {{"delimiter", ARG_STRING, false,
4889 &ds_delimiter,
4890 "Delimiter to read until"}};
4891
1/2
✓ Branch 0 taken 1389021 times.
✗ Branch 1 not taken.
1389021 DBUG_TRACE;
4892
4893
1/2
✓ Branch 0 taken 1389021 times.
✗ Branch 1 not taken.
1389021 check_command_args(command, command->first_argument, perl_args,
4894 sizeof(perl_args) / sizeof(struct command_arg), ' ');
4895
4896 1389021 ds_script = command->content;
4897 /* If it hasn't been done already by a loop iteration, fill it in */
4898
2/2
✓ Branch 0 taken 297763 times.
✓ Branch 1 taken 1091258 times.
1389021 if (!ds_script.str) {
4899 /* If no delimiter was provided, use EOF */
4900
3/4
✓ Branch 0 taken 294240 times.
✓ Branch 1 taken 3523 times.
✓ Branch 2 taken 294240 times.
✗ Branch 3 not taken.
297763 if (ds_delimiter.length == 0) dynstr_set(&ds_delimiter, "EOF");
4901
4902
1/2
✓ Branch 0 taken 297763 times.
✗ Branch 1 not taken.
297763 init_dynamic_string(&ds_script, "", 1024);
4903
1/2
✓ Branch 0 taken 297760 times.
✗ Branch 1 not taken.
297763 read_until_delimiter(&ds_script, &ds_delimiter);
4904 297760 command->content = ds_script;
4905 }
4906
4907 /* This function could be called even if "false", so check before doing */
4908
2/2
✓ Branch 0 taken 40134 times.
✓ Branch 1 taken 1348884 times.
1389018 if (cur_block->ok) {
4909
3/8
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40134 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 40134 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
40134 DBUG_PRINT("info", ("Executing perl: %s", ds_script.str));
4910
4911 /* Create temporary file name */
4912 40134 if ((fd =
4913
1/2
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
40134 create_temp_file(temp_file_path, getenv("MYSQLTEST_VARDIR"), "tmp",
4914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40134 times.
40134 O_CREAT | O_RDWR, KEEP_FILE, MYF(MY_WME))) < 0)
4915 die("Failed to create temporary file for perl command");
4916
1/2
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
40134 my_close(fd, MYF(0));
4917
4918 /* Compatibility for Perl 5.24 and newer. */
4919
1/2
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
40134 std::string script = "push @INC, \".\";\n";
4920
1/2
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
40134 script.append(ds_script.str, ds_script.length);
4921
4922
2/4
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40134 times.
✗ Branch 3 not taken.
40134 str_to_file(temp_file_path, &script[0], script.size());
4923
4924 /* Format the "perl <filename>" command */
4925 40134 snprintf(buf, sizeof(buf), "perl %s", temp_file_path);
4926
4927
3/8
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 40134 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 40134 times.
40134 if (!(res_file = popen(buf, "r")) && command->abort_on_error)
4928 die("popen(\"%s\", \"r\") failed", buf);
4929
4930
3/4
✓ Branch 0 taken 47735 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7601 times.
✓ Branch 3 taken 40134 times.
47735 while (fgets(buf, sizeof(buf), res_file)) {
4931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7601 times.
7601 if (disable_result_log) {
4932 buf[std::strlen(buf) - 1] = 0;
4933 DBUG_PRINT("exec_result", ("%s", buf));
4934 } else {
4935
1/2
✓ Branch 0 taken 7601 times.
✗ Branch 1 not taken.
7601 replace_dynstr_append(&ds_res, buf);
4936 }
4937 }
4938
1/2
✓ Branch 0 taken 40134 times.
✗ Branch 1 not taken.
40134 error = pclose(res_file);
4939
4940 /* Remove the temporary file, but keep it if perl failed */
4941
3/4
✓ Branch 0 taken 40123 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 40123 times.
✗ Branch 3 not taken.
40134 if (!error) my_delete(temp_file_path, MYF(0));
4942
4943 /* Check for error code that indicates perl could not be started */
4944 40134 int exstat = WEXITSTATUS(error);
4945 #ifdef _WIN32
4946 if (exstat == 1) /* Text must begin 'perl not found' as mtr looks for it */
4947 abort_not_supported_test("perl not found in path or did not start");
4948 #else
4949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40134 times.
40134 if (exstat == 127) abort_not_supported_test("perl not found in path");
4950 #endif
4951 else
4952
1/2
✓ Branch 0 taken 40128 times.
✗ Branch 1 not taken.
40134 handle_command_error(command, exstat);
4953 40128 }
4954
1/2
✓ Branch 0 taken 1389012 times.
✗ Branch 1 not taken.
1389012 dynstr_free(&ds_delimiter);
4955 1389012 }
4956
4957 /*
4958 Print the content between echo and <delimiter> to result file.
4959 Evaluate all variables in the string before printing, allow
4960 for variable names to be escaped using \
4961
4962 SYNOPSIS
4963 do_echo()
4964 command called command
4965
4966 DESCRIPTION
4967 echo text
4968 Print the text after echo until end of command to result file
4969
4970 echo $<var_name>
4971 Print the content of the variable <var_name> to result file
4972
4973 echo Some text $<var_name>
4974 Print "Some text" plus the content of the variable <var_name> to
4975 result file
4976
4977 echo Some text \$<var_name>
4978 Print "Some text" plus $<var_name> to result file
4979 */
4980
4981 1796419 static int do_echo(struct st_command *command) {
4982 DYNAMIC_STRING ds_echo;
4983
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 DBUG_TRACE;
4984
4985
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 init_dynamic_string(&ds_echo, "", command->query_len);
4986
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 do_eval(&ds_echo, command->first_argument, command->end, false);
4987
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length);
4988
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 dynstr_append_mem(&ds_res, "\n", 1);
4989
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 dynstr_free(&ds_echo);
4990 1796419 command->last_argument = command->end;
4991 1796419 return 0;
4992 1796419 }
4993
4994 208 static void do_wait_for_slave_to_stop(struct st_command *c [[maybe_unused]]) {
4995 static int SLAVE_POLL_INTERVAL = 300000;
4996 208 MYSQL *mysql = &cur_con->mysql;
4997 for (;;) {
4998 259 MYSQL_RES *res = nullptr;
4999 MYSQL_ROW row;
5000 int done;
5001
5002 259 if (mysql_query_wrapper(
5003 mysql,
5004 "SELECT 'Slave_running' as Variable_name,"
5005 " IF(count(*)>0,'ON','OFF') as Value FROM"
5006 " performance_schema.replication_applier_status ras,"
5007 "performance_schema.replication_connection_status rcs WHERE "
5008
2/4
✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 259 times.
518 "ras.SERVICE_STATE='ON' AND rcs.SERVICE_STATE='ON'") ||
5009
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 259 times.
259 !(res = mysql_store_result_wrapper(mysql)))
5010
5011 die("Query failed while probing slave for stop: %s", mysql_error(mysql));
5012
5013
3/6
✓ Branch 0 taken 259 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 259 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 259 times.
259 if (!(row = mysql_fetch_row_wrapper(res)) || !row[1]) {
5014 mysql_free_result_wrapper(res);
5015 die("Strange result from query while probing slave for stop");
5016 }
5017 259 done = !std::strcmp(row[1], "OFF");
5018 259 mysql_free_result_wrapper(res);
5019
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 51 times.
259 if (done) break;
5020 51 my_sleep(SLAVE_POLL_INTERVAL);
5021 51 }
5022 208 return;
5023 }
5024
5025 1734 static void do_sync_with_master2(struct st_command *command, long offset) {
5026 MYSQL_RES *res;
5027 MYSQL_ROW row;
5028 1734 MYSQL *mysql = &cur_con->mysql;
5029 char query_buf[FN_REFLEN + 128];
5030 1734 int timeout = 300; /* seconds */
5031
5032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1734 times.
1734 if (!master_pos.file[0])
5033 die("Calling 'sync_with_master' without calling 'save_master_pos'");
5034
5035 1734 sprintf(query_buf, "select source_pos_wait('%s', %ld, %d)", master_pos.file,
5036 1734 master_pos.pos + offset, timeout);
5037
5038
2/4
✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1734 times.
1734 if (mysql_query_wrapper(mysql, query_buf))
5039 die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql),
5040 mysql_error(mysql));
5041
5042
2/4
✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1734 times.
1734 if (!(res = mysql_store_result_wrapper(mysql)))
5043 die("mysql_store_result() returned NULL for '%s'", query_buf);
5044
2/4
✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1734 times.
1734 if (!(row = mysql_fetch_row_wrapper(res))) {
5045 mysql_free_result_wrapper(res);
5046 die("empty result in %s", query_buf);
5047 }
5048
5049 1734 int result = -99;
5050 1734 const char *result_str = row[0];
5051
1/2
✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
1734 if (result_str) result = atoi(result_str);
5052
5053
1/2
✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
1734 mysql_free_result_wrapper(res);
5054
5055
2/4
✓ Branch 0 taken 1734 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1734 times.
1734 if (!result_str || result < 0) {
5056 /* source_pos_wait returned NULL or < 0 */
5057 show_query(mysql, "SHOW MASTER STATUS");
5058 show_query(mysql, "SHOW SLAVE STATUS");
5059 show_query(mysql, "SHOW PROCESSLIST");
5060 fprintf(stderr, "analyze: sync_with_master\n");
5061
5062 if (!result_str) {
5063 /*
5064 source_pos_wait returned NULL. This indicates that
5065 slave SQL thread is not started, the slave's master
5066 information is not initialized, the arguments are
5067 incorrect, or an error has occurred
5068 */
5069 die("%.*s failed: '%s' returned NULL "
5070 "indicating slave SQL thread failure",
5071 static_cast<int>(command->first_word_len), command->query, query_buf);
5072 }
5073
5074 if (result == -1)
5075 die("%.*s failed: '%s' returned -1 "
5076 "indicating timeout after %d seconds",
5077 static_cast<int>(command->first_word_len), command->query, query_buf,
5078 timeout);
5079 else
5080 die("%.*s failed: '%s' returned unknown result :%d",
5081 static_cast<int>(command->first_word_len), command->query, query_buf,
5082 result);
5083 }
5084
5085 3468 return;
5086 }
5087
5088 185 static void do_sync_with_master(struct st_command *command) {
5089 185 long offset = 0;
5090 185 char *p = command->first_argument;
5091 185 const char *offset_start = p;
5092
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 175 times.
185 if (*offset_start) {
5093
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for (; my_isdigit(charset_info, *p); p++) offset = offset * 10 + *p - '0';
5094
5095
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
10 if (*p && !my_isspace(charset_info, *p))
5096 6 die("Invalid integer argument \"%s\"", offset_start);
5097 4 command->last_argument = p;
5098 }
5099 179 do_sync_with_master2(command, offset);
5100 179 return;
5101 }
5102
5103 /*
5104 Wait for ndb binlog injector to be up-to-date with all changes
5105 done on the local mysql server
5106 */
5107
5108 1787 static void ndb_wait_for_binlog_injector(void) {
5109 MYSQL_RES *res;
5110 MYSQL_ROW row;
5111 1787 MYSQL *mysql = &cur_con->mysql;
5112 const char *query;
5113 ulong have_ndbcluster;
5114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1787 times.
1787 if (mysql_query_wrapper(
5115 mysql, query = "select count(*) from information_schema.engines"
5116 " where engine = 'ndbcluster' and"
5117 " support in ('YES', 'DEFAULT')"))
5118 die("'%s' failed: %d %s", query, mysql_errno(mysql), mysql_error(mysql));
5119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1787 times.
1787 if (!(res = mysql_store_result_wrapper(mysql)))
5120 die("mysql_store_result() returned NULL for '%s'", query);
5121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1787 times.
1787 if (!(row = mysql_fetch_row_wrapper(res)))
5122 die("Query '%s' returned empty result", query);
5123
5124 1787 have_ndbcluster = std::strcmp(row[0], "1") == 0;
5125 1787 mysql_free_result_wrapper(res);
5126
5127
1/2
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
1787 if (!have_ndbcluster) {
5128 1787 return;
5129 }
5130
5131 ulonglong start_epoch = 0, handled_epoch = 0, latest_trans_epoch = 0,
5132 latest_handled_binlog_epoch = 0, start_handled_binlog_epoch = 0;
5133 const int WaitSeconds = 150;
5134
5135 int count = 0;
5136 int do_continue = 1;
5137 while (do_continue) {
5138 const char binlog[] = "binlog";
5139 const char latest_trans_epoch_str[] = "latest_trans_epoch=";
5140 const char latest_handled_binlog_epoch_str[] =
5141 "latest_handled_binlog_epoch=";
5142 if (count) my_sleep(100 * 1000); /* 100ms */
5143
5144 if (mysql_query_wrapper(mysql, query = "show engine ndb status"))
5145 die("failed in '%s': %d %s", query, mysql_errno(mysql),
5146 mysql_error(mysql));
5147
5148 if (!(res = mysql_store_result_wrapper(mysql)))
5149 die("mysql_store_result() returned NULL for '%s'", query);
5150
5151 while ((row = mysql_fetch_row_wrapper(res))) {
5152 if (std::strcmp(row[1], binlog) == 0) {
5153 const char *status = row[2];
5154
5155 /* latest_trans_epoch */
5156 while (*status && std::strncmp(status, latest_trans_epoch_str,
5157 sizeof(latest_trans_epoch_str) - 1))
5158 status++;
5159 if (*status) {
5160 status += sizeof(latest_trans_epoch_str) - 1;
5161 latest_trans_epoch = my_strtoull(status, (char **)nullptr, 10);
5162 } else
5163 die("result does not contain '%s' in '%s'", latest_trans_epoch_str,
5164 query);
5165
5166 /* latest_handled_binlog */
5167 while (*status &&
5168 std::strncmp(status, latest_handled_binlog_epoch_str,
5169 sizeof(latest_handled_binlog_epoch_str) - 1))
5170 status++;
5171 if (*status) {
5172 status += sizeof(latest_handled_binlog_epoch_str) - 1;
5173 latest_handled_binlog_epoch =
5174 my_strtoull(status, (char **)nullptr, 10);
5175 } else
5176 die("result does not contain '%s' in '%s'",
5177 latest_handled_binlog_epoch_str, query);
5178
5179 if (count == 0) {
5180 start_epoch = latest_trans_epoch;
5181 start_handled_binlog_epoch = latest_handled_binlog_epoch;
5182 }
5183 break;
5184 }
5185 }
5186 if (!row) die("result does not contain '%s' in '%s'", binlog, query);
5187 if (latest_handled_binlog_epoch > handled_epoch) count = 0;
5188 handled_epoch = latest_handled_binlog_epoch;
5189 count++;
5190 if (latest_handled_binlog_epoch >= start_epoch)
5191 do_continue = 0;
5192 else if (count > (WaitSeconds * 10)) {
5193 die("do_save_master_pos() timed out after %u s waiting for "
5194 "last committed epoch to be applied by the "
5195 "Ndb binlog injector. "
5196 "Ndb epoch %llu/%llu to be handled. "
5197 "Last handled epoch : %llu/%llu. "
5198 "First handled epoch : %llu/%llu.",
5199 WaitSeconds, start_epoch >> 32, start_epoch & 0xffffffff,
5200 latest_handled_binlog_epoch >> 32,
5201 latest_handled_binlog_epoch & 0xffffffff,
5202 start_handled_binlog_epoch >> 32,
5203 start_handled_binlog_epoch & 0xffffffff);
5204 }
5205
5206 mysql_free_result_wrapper(res);
5207 }
5208 }
5209
5210 1787 static int do_save_master_pos() {
5211 MYSQL_RES *res;
5212 MYSQL_ROW row;
5213 1787 MYSQL *mysql = &cur_con->mysql;
5214 const char *query;
5215
1/2
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
1787 DBUG_TRACE;
5216 /*
5217 when ndb binlog is on, this call will wait until last updated epoch
5218 (locally in the mysqld) has been received into the binlog
5219 */
5220
1/2
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
1787 ndb_wait_for_binlog_injector();
5221
5222
2/4
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1787 times.
1787 if (mysql_query_wrapper(mysql, query = "show master status"))
5223 die("failed in 'show master status': %d %s", mysql_errno(mysql),
5224 mysql_error(mysql));
5225
5226
2/4
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1787 times.
1787 if (!(res = mysql_store_result_wrapper(mysql)))
5227 die("mysql_store_result() retuned NULL for '%s'", query);
5228
2/4
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1787 times.
1787 if (!(row = mysql_fetch_row_wrapper(res)))
5229 die("empty result in show master status");
5230 1787 my_stpnmov(master_pos.file, row[0], sizeof(master_pos.file) - 1);
5231 1787 master_pos.pos = strtoul(row[1], (char **)nullptr, 10);
5232
1/2
✓ Branch 0 taken 1787 times.
✗ Branch 1 not taken.
1787 mysql_free_result_wrapper(res);
5233 1787 return 0;
5234 1787 }
5235
5236 /*
5237 Check if a variable name is valid or not.
5238
5239 SYNOPSIS
5240 check_variable_name()
5241 var_name - pointer to the beginning of variable name
5242 var_name_end - pointer to the end of variable name
5243 dollar_flag - flag to check whether variable name should start with '$'
5244 */
5245 203934 static void check_variable_name(const char *var_name, const char *var_name_end,
5246 const bool dollar_flag) {
5247 char save_var_name[MAX_VAR_NAME_LENGTH];
5248
1/2
✓ Branch 0 taken 203934 times.
✗ Branch 1 not taken.
203934 strmake(save_var_name, var_name, (var_name_end - var_name));
5249
5250 // Check if variable name should start with '$'
5251
4/4
✓ Branch 0 taken 135950 times.
✓ Branch 1 taken 67984 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 135947 times.
203934 if (!dollar_flag && (*var_name != '$'))
5252 3 die("Variable name '%s' should start with '$'", save_var_name);
5253
5254
2/2
✓ Branch 0 taken 203928 times.
✓ Branch 1 taken 3 times.
203931 if (*var_name == '$') var_name++;
5255
5256 // Check if variable name exists or not
5257
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 203928 times.
203931 if (var_name == var_name_end) die("Missing variable name.");
5258
5259 // Check for non alphanumeric character(s) in variable name
5260
6/6
✓ Branch 0 taken 2055379 times.
✓ Branch 1 taken 203922 times.
✓ Branch 2 taken 1911976 times.
✓ Branch 3 taken 143403 times.
✓ Branch 4 taken 143397 times.
✓ Branch 5 taken 6 times.
2259301 while ((var_name != var_name_end) && my_isvar(charset_info, *var_name))
5261 2055373 var_name++;
5262
5263
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203922 times.
203928 if (var_name != var_name_end)
5264 6 die("Invalid variable name '%s'", save_var_name);
5265 203922 }
5266
5267 /*
5268 Check if the pointer points to an operator.
5269
5270 SYNOPSIS
5271 is_operator()
5272 op - character pointer to mathematical expression
5273 */
5274 1136549 static bool is_operator(const char *op) {
5275
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 if (*op == '+')
5276 return true;
5277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '-')
5278 return true;
5279
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '*')
5280 return true;
5281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '/')
5282 return true;
5283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '%')
5284 return true;
5285
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1136549 else if (*op == '&' && *(op + 1) == '&')
5286 return true;
5287
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1136549 else if (*op == '|' && *(op + 1) == '|')
5288 return true;
5289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '&')
5290 return true;
5291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '|')
5292 return true;
5293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
1136549 else if (*op == '^')
5294 return true;
5295
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1136549 else if (*op == '>' && *(op + 1) == '>')
5296 return true;
5297
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1136549 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1136549 else if (*op == '<' && *(op + 1) == '<')
5298 return true;
5299
5300 1136549 return false;
5301 }
5302
5303 /*
5304 Perform basic mathematical operation.
5305
5306 SYNOPSIS
5307 do_expr()
5308 command - command handle
5309
5310 DESCRIPTION
5311 expr $<var_name>= <operand1> <operator> <operand2>
5312 Perform basic mathematical operation and store the result
5313 in a variable($<var_name>). Both <operand1> and <operand2>
5314 should be valid MTR variables.
5315
5316 'expr' command supports only binary operators that operates
5317 on two operands and manipulates them to return a result.
5318
5319 Following mathematical operators are supported.
5320 1 Arithmetic Operators
5321 1.1 Addition
5322 1.2 Subtraction
5323 1.3 Multiplication
5324 1.4 Division
5325 1.5 Modulo
5326
5327 2 Logical Operators
5328 2.1 Logical AND
5329 2.2 Logical OR
5330
5331 3 Bitwise Operators
5332 3.1 Binary AND
5333 3.2 Binary OR
5334 3.3 Binary XOR
5335 3.4 Binary Left Shift
5336 3.5 Binary Right Shift
5337
5338 NOTE
5339 1. Non-integer operand is truncated to integer value for operations
5340 that dont support non-integer operand.
5341 2. If the result is an infinite value, then expr command will return
5342 'inf' keyword to indicate the result is infinity.
5343 3. Division by 0 will result in an infinite value and expr command
5344 will return 'inf' keyword to indicate the result is infinity.
5345 */
5346 67987 static void do_expr(struct st_command *command) {
5347
1/2
✓ Branch 0 taken 67987 times.
✗ Branch 1 not taken.
67987 DBUG_TRACE;
5348
5349 67987 const char *p = command->first_argument;
5350
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 67984 times.
67987 if (!*p) die("Missing arguments to expr command.");
5351
5352 // Find <var_name>
5353 67984 const char *var_name = p;
5354
6/6
✓ Branch 0 taken 564462 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 564108 times.
✓ Branch 3 taken 354 times.
✓ Branch 4 taken 496481 times.
✓ Branch 5 taken 67627 times.
564465 while (*p && (*p != '=') && !my_isspace(charset_info, *p)) p++;
5355 67984 const char *var_name_end = p;
5356
1/2
✓ Branch 0 taken 67981 times.
✗ Branch 1 not taken.
67984 check_variable_name(var_name, var_name_end, true);
5357
5358 // Skip spaces between <var_name> and '='
5359
2/2
✓ Branch 0 taken 67627 times.
✓ Branch 1 taken 67981 times.
135608 while (my_isspace(charset_info, *p)) p++;
5360
5361
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 67978 times.
67981 if (*p++ != '=') die("Missing assignment operator in expr command.");
5362
5363 // Skip spaces after '='
5364
3/4
✓ Branch 0 taken 135955 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67977 times.
✓ Branch 3 taken 67978 times.
135955 while (*p && my_isspace(charset_info, *p)) p++;
5365
5366 // Save the mathematical expression in a variable
5367 67978 const char *expr = p;
5368
5369 // First operand in the expression
5370 67978 const char *operand_name = p;
5371
7/8
✓ Branch 0 taken 1136549 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1136549 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1068574 times.
✓ Branch 5 taken 67975 times.
✓ Branch 6 taken 1068574 times.
✓ Branch 7 taken 67978 times.
1136552 while (*p && !is_operator(p) && !my_isspace(charset_info, *p)) p++;
5372 67978 const char *operand_name_end = p;
5373
1/2
✓ Branch 0 taken 67978 times.
✗ Branch 1 not taken.
67978 check_variable_name(operand_name, operand_name_end, false);
5374
1/2
✓ Branch 0 taken 67978 times.
✗ Branch 1 not taken.
67978 VAR *v1 = var_get(operand_name, &operand_name_end, false, false);
5375
5376 double operand1;
5377
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 67948 times.
67978 if ((my_isdigit(charset_info, *v1->str_val)) ||
5378
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
30 ((*v1->str_val == '-') && my_isdigit(charset_info, *(v1->str_val + 1))))
5379 67972 operand1 = strtod(v1->str_val, nullptr);
5380 else
5381 6 die("Undefined/invalid first operand '$%s' in expr command.", v1->name);
5382
5383 // Skip spaces after the first operand
5384
3/4
✓ Branch 0 taken 135944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67972 times.
✓ Branch 3 taken 67972 times.
135944 while (*p && my_isspace(charset_info, *p)) p++;
5385
5386 // Extract the operator
5387 67972 const char *operator_start = p;
5388
2/4
✓ Branch 0 taken 135998 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 135998 times.
✗ Branch 3 not taken.
135998 while (*p && (*p != '$') &&
5389
4/6
✓ Branch 0 taken 68026 times.
✓ Branch 1 taken 67972 times.
✓ Branch 2 taken 68026 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 68026 times.
✗ Branch 5 not taken.
135998 !(my_isspace(charset_info, *p) || my_isvar(charset_info, *p)))
5390 68026 p++;
5391
5392 char math_operator[3];
5393
1/2
✓ Branch 0 taken 67972 times.
✗ Branch 1 not taken.
67972 strmake(math_operator, operator_start, (p - operator_start));
5394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67972 times.
67972 if (!std::strlen(math_operator))
5395 die("Missing mathematical operator in expr command.");
5396
5397 // Skip spaces after the operator
5398
3/4
✓ Branch 0 taken 135944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67972 times.
✓ Branch 3 taken 67972 times.
135944 while (*p && my_isspace(charset_info, *p)) p++;
5399
5400 // Second operand in the expression
5401 67972 operand_name = p;
5402
4/4
✓ Branch 0 taken 694264 times.
✓ Branch 1 taken 67969 times.
✓ Branch 2 taken 694261 times.
✓ Branch 3 taken 3 times.
762233 while (*p && !my_isspace(charset_info, *p)) p++;
5403 67972 operand_name_end = p;
5404
1/2
✓ Branch 0 taken 67963 times.
✗ Branch 1 not taken.
67972 check_variable_name(operand_name, operand_name_end, false);
5405
1/2
✓ Branch 0 taken 67963 times.
✗ Branch 1 not taken.
67963 VAR *v2 = var_get(operand_name, &operand_name_end, false, false);
5406
5407 double operand2;
5408
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 67920 times.
67963 if ((my_isdigit(charset_info, *v2->str_val)) ||
5409
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 3 times.
43 ((*v2->str_val == '-') && my_isdigit(charset_info, *(v2->str_val + 1))))
5410 67957 operand2 = strtod(v2->str_val, nullptr);
5411 else
5412 6 die("Undefined/invalid second operand '$%s' in expr command.", v2->name);
5413
5414 // Skip spaces at the end
5415
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 67954 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
67960 while (*p && my_isspace(charset_info, *p)) p++;
5416
5417 // Check for any spurious text after the second operand
5418
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 67954 times.
67957 if (*p) die("Invalid mathematical expression '%s' in expr command.", expr);
5419
5420 double result;
5421 // Arithmetic Operators
5422
2/2
✓ Branch 0 taken 1798 times.
✓ Branch 1 taken 66156 times.
67954 if (!std::strcmp(math_operator, "+"))
5423 1798 result = operand1 + operand2;
5424
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 66133 times.
66156 else if (!std::strcmp(math_operator, "-"))
5425 23 result = operand1 - operand2;
5426
2/2
✓ Branch 0 taken 66019 times.
✓ Branch 1 taken 114 times.
66133 else if (!std::strcmp(math_operator, "*"))
5427 66019 result = operand1 * operand2;
5428
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 96 times.
114 else if (!std::strcmp(math_operator, "/")) {
5429
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
18 if (operand2 == 0.0) {
5430
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (operand1 == 0.0)
5431 3 result = std::numeric_limits<double>::quiet_NaN();
5432 else
5433 3 result = std::numeric_limits<double>::infinity();
5434 } else
5435 12 result = operand1 / operand2;
5436
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 87 times.
96 } else if (!std::strcmp(math_operator, "%"))
5437 9 result = (int)operand1 % (int)operand2;
5438 // Logical Operators
5439
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 69 times.
87 else if (!std::strcmp(math_operator, "&&"))
5440
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6 times.
18 result = operand1 && operand2;
5441
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 54 times.
69 else if (!std::strcmp(math_operator, "||"))
5442
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
15 result = operand1 || operand2;
5443 // Bitwise Operators
5444
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 42 times.
54 else if (!std::strcmp(math_operator, "&"))
5445 12 result = (int)operand1 & (int)operand2;
5446
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
42 else if (!std::strcmp(math_operator, "|"))
5447 12 result = (int)operand1 | (int)operand2;
5448
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 21 times.
30 else if (!std::strcmp(math_operator, "^"))
5449 9 result = (int)operand1 ^ (int)operand2;
5450
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 12 times.
21 else if (!std::strcmp(math_operator, ">>"))
5451 9 result = (int)operand1 >> (int)operand2;
5452
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
12 else if (!std::strcmp(math_operator, "<<"))
5453 9 result = (int)operand1 << (int)operand2;
5454 else
5455 3 die("Invalid operator '%s' in expr command", math_operator);
5456
5457 char buf[128];
5458 size_t result_len;
5459 // Check if result is an infinite value
5460
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 67948 times.
67951 if (std::isnan(result)) {
5461 // Print 'nan' if result is Not a Number
5462 3 result_len = snprintf(buf, sizeof(buf), "%s", "nan");
5463
2/2
✓ Branch 0 taken 67942 times.
✓ Branch 1 taken 6 times.
67948 } else if (!std::isinf(result)) {
5464
3/4
✓ Branch 0 taken 67933 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 67933 times.
✗ Branch 3 not taken.
67942 const char *format = (result < 1e10 && result > -1e10) ? "%f" : "%g";
5465 67942 result_len = snprintf(buf, sizeof(buf), format, result);
5466 } else
5467 // Print 'inf' if result is an infinite value
5468 6 result_len = snprintf(buf, sizeof(buf), "%s", "inf");
5469
5470
3/4
✓ Branch 0 taken 67933 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 67933 times.
✗ Branch 3 not taken.
67951 if (result < 1e10 && result > -1e10) {
5471 /*
5472 Remove the trailing 0's i.e 2.0000000 need to be represented
5473 as 2 for consistency, 2.0010000 also becomes 2.001.
5474 */
5475
2/2
✓ Branch 0 taken 407583 times.
✓ Branch 1 taken 67933 times.
475516 while (buf[result_len - 1] == '0') result_len--;
5476
5477 // Remove trailing '.' if exists
5478
2/2
✓ Branch 0 taken 67921 times.
✓ Branch 1 taken 12 times.
67933 if (buf[result_len - 1] == '.') result_len--;
5479 }
5480
5481
1/2
✓ Branch 0 taken 67951 times.
✗ Branch 1 not taken.
67951 var_set(var_name, var_name_end, buf, buf + result_len);
5482 67951 command->last_argument = command->end;
5483 67951 }
5484
5485 /*
5486 Assign the variable <var_name> with <var_val>
5487
5488 SYNOPSIS
5489 do_let()
5490 query called command
5491
5492 DESCRIPTION
5493 let $<var_name>=<var_val><delimiter>
5494
5495 <var_name> - is the string string found between the $ and =
5496 <var_val> - is the content between the = and <delimiter>, it may span
5497 multiple line and contain any characters except <delimiter>
5498 <delimiter> - is a string containing of one or more chars, default is ;
5499
5500 RETURN VALUES
5501 Program will die if error detected
5502 */
5503
5504 19740166 static void do_let(struct st_command *command) {
5505 19740166 const char *p = command->first_argument;
5506 const char *var_name, *var_name_end;
5507 DYNAMIC_STRING let_rhs_expr;
5508
1/2
✓ Branch 0 taken 19740166 times.
✗ Branch 1 not taken.
19740166 DBUG_TRACE;
5509
5510
1/2
✓ Branch 0 taken 19740166 times.
✗ Branch 1 not taken.
19740166 init_dynamic_string(&let_rhs_expr, "", 512);
5511
5512 /* Find <var_name> */
5513
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19740163 times.
19740166 if (!*p) die("Missing arguments to let");
5514 19740163 var_name = p;
5515
6/6
✓ Branch 0 taken 435809412 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 420324165 times.
✓ Branch 3 taken 15485247 times.
✓ Branch 4 taken 416069255 times.
✓ Branch 5 taken 4254910 times.
435809418 while (*p && (*p != '=') && !my_isspace(charset_info, *p)) p++;
5516 19740163 var_name_end = p;
5517
2/2
✓ Branch 0 taken 19740160 times.
✓ Branch 1 taken 3 times.
19740163 if (var_name == var_name_end ||
5518
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 19740127 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 27 times.
19740160 (var_name + 1 == var_name_end && *var_name == '$'))
5519 9 die("Missing variable name in let");
5520
2/2
✓ Branch 0 taken 18603473 times.
✓ Branch 1 taken 19740154 times.
38343627 while (my_isspace(charset_info, *p)) p++;
5521
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 19740142 times.
19740154 if (*p++ != '=') die("Missing assignment operator in let");
5522
5523 /* Find start of <var_val> */
5524
4/4
✓ Branch 0 taken 35133451 times.
✓ Branch 1 taken 2125313 times.
✓ Branch 2 taken 17518622 times.
✓ Branch 3 taken 17614829 times.
37258764 while (*p && my_isspace(charset_info, *p)) p++;
5525
5526
1/2
✓ Branch 0 taken 19740142 times.
✗ Branch 1 not taken.
19740142 do_eval(&let_rhs_expr, p, command->end, false);
5527
5528 19740142 command->last_argument = command->end;
5529 /* Assign var_val to var_name */
5530 19740142 var_set(var_name, var_name_end, let_rhs_expr.str,
5531
1/2
✓ Branch 0 taken 19740087 times.
✗ Branch 1 not taken.
19740142 (let_rhs_expr.str + let_rhs_expr.length));
5532
1/2
✓ Branch 0 taken 19740087 times.
✗ Branch 1 not taken.
19740087 dynstr_free(&let_rhs_expr);
5533
1/2
✓ Branch 0 taken 19740087 times.
✗ Branch 1 not taken.
19740087 revert_properties();
5534 19740087 }
5535
5536 /*
5537 Sleep the number of specified seconds
5538
5539 SYNOPSIS
5540 do_sleep()
5541 q called command
5542
5543 DESCRIPTION
5544 Sleep <seconds>
5545
5546 The argument provided to --sleep command is not required to be
5547 a whole number and can have fractional parts as well. For
5548 example, '--sleep 0.1' is valid.
5549
5550 */
5551
5552 524906 static int do_sleep(struct st_command *command) {
5553 524906 int error = 0;
5554 double sleep_val;
5555 char *p;
5556 static DYNAMIC_STRING ds_sleep;
5557 524906 const struct command_arg sleep_args[] = {{"sleep_delay", ARG_STRING, true,
5558 &ds_sleep,
5559 "Number of seconds to sleep."}};
5560
1/2
✓ Branch 0 taken 524894 times.
✗ Branch 1 not taken.
524906 check_command_args(command, command->first_argument, sleep_args,
5561 sizeof(sleep_args) / sizeof(struct command_arg), ' ');
5562
5563 524894 p = ds_sleep.str;
5564 524894 const char *sleep_end = ds_sleep.str + ds_sleep.length;
5565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524894 times.
524894 while (my_isspace(charset_info, *p)) p++;
5566
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524894 times.
524894 if (!*p)
5567 die("Missing argument to %.*s", static_cast<int>(command->first_word_len),
5568 command->query);
5569 524894 const char *sleep_start = p;
5570 /* Check that arg starts with a digit, not handled by my_strtod */
5571
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 524888 times.
524894 if (!my_isdigit(charset_info, *sleep_start))
5572 6 die("Invalid argument to %.*s \"%s\"",
5573 6 static_cast<int>(command->first_word_len), command->query, sleep_start);
5574
1/2
✓ Branch 0 taken 524888 times.
✗ Branch 1 not taken.
524888 sleep_val = my_strtod(sleep_start, &sleep_end, &error);
5575
1/2
✓ Branch 0 taken 524885 times.
✗ Branch 1 not taken.
524888 check_eol_junk_line(sleep_end);
5576
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 524885 times.
524885 if (error)
5577 die("Invalid argument to %.*s \"%s\"",
5578 static_cast<int>(command->first_word_len), command->query,
5579 command->first_argument);
5580
1/2
✓ Branch 0 taken 524885 times.
✗ Branch 1 not taken.
524885 dynstr_free(&ds_sleep);
5581
5582
3/8
✓ Branch 0 taken 524885 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 524885 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 524885 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
524885 DBUG_PRINT("info", ("sleep_val: %f", sleep_val));
5583
2/4
✓ Branch 0 taken 524885 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 524885 times.
✗ Branch 3 not taken.
524885 if (sleep_val) my_sleep((ulong)(sleep_val * 1000000L));
5584 524885 return 0;
5585 }
5586
5587 271 static void do_set_charset(struct st_command *command) {
5588 271 char *charset_name = command->first_argument;
5589 char *p;
5590
5591
2/4
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 271 times.
271 if (!charset_name || !*charset_name)
5592 die("Missing charset name in 'character_set'");
5593 /* Remove end space */
5594 271 p = charset_name;
5595
3/4
✓ Branch 0 taken 1445 times.
✓ Branch 1 taken 271 times.
✓ Branch 2 taken 1445 times.
✗ Branch 3 not taken.
1716 while (*p && !my_isspace(charset_info, *p)) p++;
5596
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 if (*p) *p++ = 0;
5597 271 command->last_argument = p;
5598 271 charset_info =
5599 271 get_charset_by_csname(charset_name, MY_CS_PRIMARY, MYF(MY_WME));
5600
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 if (!charset_info)
5601 abort_not_supported_test("Test requires charset '%s'", charset_name);
5602 271 }
5603
5604 /// Check if the bug number argument to disable_testcase is in a proper
5605 /// format.
5606 ///
5607 /// Bug number argument should follow 'BUG#XXXX' format
5608 ///
5609 /// - Keyword 'BUG" is case-insensitive
5610 /// - XXXX should contain only digits
5611 ///
5612 /// @param bug_number String representing a bug number
5613 ///
5614 /// @retval True if the bug number argument is in correct format, false
5615 /// otherwise.
5616 72 static bool validate_bug_number_argument(std::string bug_number) {
5617 // Convert the string to lowercase characters
5618 72 std::transform(bug_number.begin(), bug_number.end(), bug_number.begin(),
5619 ::tolower);
5620
5621 // Check if string representing a bug number starts 'BUG' keyword.
5622 // Note: This keyword is case-inseinsitive.
5623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (bug_number.substr(0, 3).compare("bug") != 0) return false;
5624
5625 // Check if the string contains '#' after 'BUG' keyword
5626
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 69 times.
72 if (bug_number.at(3) != '#') return false;
5627
5628 // Check if the bug number string contains only digits after '#'
5629
3/4
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 63 times.
69 if (get_int_val(bug_number.substr(4).c_str()) == -1) return false;
5630
5631 63 return true;
5632 }
5633
5634 /// Disable or don't execute the statements or commands appear after
5635 /// this command until the execution is enabled by 'enable_testcase'
5636 /// command. If test cases are already disabled, then throw an error
5637 /// and abort the test execution.
5638 ///
5639 /// This command also takes a mandatory parameter specifying the bug
5640 /// number.
5641 ///
5642 /// @code
5643 /// --disable_testcase BUG#XXXX
5644 /// statements or commands
5645 /// --enable_testcase
5646 /// @endcode
5647 ///
5648 /// @param command Pointer to the st_command structure which holds the
5649 /// arguments and information for the command.
5650 72 static void do_disable_testcase(struct st_command *command) {
5651 DYNAMIC_STRING ds_bug_number;
5652 72 const struct command_arg disable_testcase_args[] = {
5653 72 {"Bug number", ARG_STRING, true, &ds_bug_number, "Bug number"}};
5654
5655
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 check_command_args(command, command->first_argument, disable_testcase_args,
5656 sizeof(disable_testcase_args) / sizeof(struct command_arg),
5657 ' ');
5658
5659 /// Check if the bug number argument to disable_testcase is in a
5660 /// proper format.
5661
4/6
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 63 times.
72 if (validate_bug_number_argument(ds_bug_number.str) == 0) {
5662
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 free_dynamic_strings(&ds_bug_number);
5663 9 die("Bug number mentioned in '%s' command is not in a correct format. "
5664 "It should be 'BUG#XXXX', where keyword 'BUG' is case-insensitive "
5665 "and 'XXXX' should contain only digits.",
5666 command->query);
5667 }
5668
5669 63 testcase_disabled = true;
5670
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
63 free_dynamic_strings(&ds_bug_number);
5671 63 }
5672
5673 /**
5674 A wrapper around kill call that prints diagnostics if the call failed with
5675 any other error than ESRCH.
5676
5677 @param pid Process id
5678 @param sig Signal to send to process
5679 @return The return value of kill call
5680 */
5681 21319 static int my_kill(int pid, int sig) {
5682 21319 const int result = kill(pid, sig);
5683
3/4
✓ Branch 0 taken 3111 times.
✓ Branch 1 taken 18208 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3111 times.
21319 if (result == -1 && errno != ESRCH) {
5684 log_msg("kill(%d, %d) returned errno %d (%s)", pid, sig, errno,
5685 strerror(errno));
5686 }
5687 21319 return result;
5688 }
5689
5690 /**
5691 Check if process is active.
5692
5693 @param pid Process id.
5694
5695 @return true if process is active, false otherwise.
5696 */
5697 20881 static bool is_process_active(int pid) {
5698 #ifdef _WIN32
5699 DWORD exit_code;
5700 HANDLE proc;
5701 proc = OpenProcess(PROCESS_QUERY_INFORMATION, false, pid);
5702 if (proc == NULL) return false; /* Process could not be found. */
5703
5704 if (!GetExitCodeProcess(proc, &exit_code)) exit_code = 0;
5705
5706 CloseHandle(proc);
5707 if (exit_code != STILL_ACTIVE)
5708 return false; /* Error or process has terminated. */
5709
5710 return true;
5711 #else
5712 20881 return (my_kill(pid, 0) == 0);
5713 #endif
5714 }
5715
5716 /**
5717 kill process.
5718
5719 @param pid Process id.
5720
5721 @return true if process is terminated, false otherwise.
5722 */
5723 438 static bool kill_process(int pid) {
5724 438 bool killed = true;
5725 #ifdef _WIN32
5726 HANDLE proc;
5727 proc = OpenProcess(PROCESS_TERMINATE, false, pid);
5728 if (proc == NULL) return true; /* Process could not be found. */
5729
5730 if (!TerminateProcess(proc, 201)) killed = false;
5731
5732 CloseHandle(proc);
5733 #else
5734 438 killed = (my_kill(pid, SIGKILL) == 0);
5735 #endif
5736 438 return killed;
5737 }
5738
5739 /**
5740 Abort process.
5741
5742 @param pid Process id.
5743 @param path Path to create minidump file in.
5744 */
5745 static void abort_process(int pid, const char *path [[maybe_unused]]) {
5746 #ifdef _WIN32
5747 HANDLE proc;
5748 proc = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
5749 verbose_msg("Aborting pid %d (handle: %p)\n", pid, proc);
5750 if (proc != NULL) {
5751 char name[FN_REFLEN], *end;
5752 BOOL is_debugged;
5753
5754 if (path) {
5755 /* Append mysqld.<pid>.dmp to the path. */
5756 strncpy(name, path, sizeof(name) - 1);
5757 name[sizeof(name) - 1] = '\0';
5758 end = name + std::strlen(name);
5759 /* Make sure "/mysqld.nnnnnnnnnn.dmp" fits */
5760 if ((end - name) < (sizeof(name) - 23)) {
5761 if (!is_directory_separator(end[-1])) {
5762 end[0] = FN_LIBCHAR2; // datadir path normally uses '/'.
5763 end++;
5764 }
5765 snprintf(end, sizeof(name) + name - end - 1, "mysqld.%d.dmp", pid);
5766
5767 verbose_msg("Creating minidump.\n");
5768 my_create_minidump(name, proc, pid);
5769 } else
5770 die("Path too long for creating minidump!\n");
5771 }
5772 /* If running in a debugger, send a break, otherwise terminate. */
5773 if (CheckRemoteDebuggerPresent(proc, &is_debugged) && is_debugged) {
5774 if (!DebugBreakProcess(proc)) {
5775 DWORD err = GetLastError();
5776 verbose_msg("DebugBreakProcess failed: %d\n", err);
5777 } else
5778 verbose_msg("DebugBreakProcess succeeded!\n");
5779 CloseHandle(proc);
5780 } else {
5781 CloseHandle(proc);
5782 (void)kill_process(pid);
5783 }
5784 } else {
5785 DWORD err = GetLastError();
5786 verbose_msg("OpenProcess failed: %d\n", err);
5787 }
5788 #else
5789 log_msg("shutdown_server timeout exceeded, SIGABRT set to the server PID %d",
5790 pid);
5791 my_kill(pid, SIGABRT);
5792 #endif
5793 }
5794
5795 /// Shutdown or kill the server. If timeout is set to 0 the server is
5796 /// killed or terminated immediately. Otherwise the shutdown command
5797 /// is first sent and then it waits for the server to terminate within
5798 /// 'timeout' seconds. If it has not terminated before 'timeout'
5799 /// seconds the command will fail.
5800 ///
5801 /// @note
5802 /// Currently only works with local server
5803 ///
5804 /// @param command Pointer to the st_command structure which holds the
5805 /// arguments and information for the command. Optionally
5806 /// including a timeout else the default of 60 seconds
5807 3549 static void do_shutdown_server(struct st_command *command) {
5808 static DYNAMIC_STRING ds_timeout;
5809 3549 const struct command_arg shutdown_args[] = {
5810 {"timeout", ARG_STRING, false, &ds_timeout,
5811 "Timeout before killing server"}};
5812
5813
1/2
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
3549 check_command_args(command, command->first_argument, shutdown_args,
5814 sizeof(shutdown_args) / sizeof(struct command_arg), ' ');
5815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3549 times.
3549 if (opt_offload_count_file) {
5816 // Save the value of secondary engine execution status
5817 // before shutting down the server.
5818 if (secondary_engine->offload_count(&cur_con->mysql, "after"))
5819 cleanup_and_exit(1);
5820 }
5821
5822 3549 long timeout = 600;
5823
5824
2/2
✓ Branch 0 taken 3046 times.
✓ Branch 1 taken 503 times.
3549 if (ds_timeout.length) {
5825 char *endptr;
5826 3046 timeout = std::strtol(ds_timeout.str, &endptr, 10);
5827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3046 times.
3046 if (*endptr != '\0')
5828 die("Illegal argument for timeout: '%s'", ds_timeout.str);
5829 }
5830
5831
1/2
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
3549 dynstr_free(&ds_timeout);
5832
5833 3549 MYSQL *mysql = &cur_con->mysql;
5834 3549 std::string ds_file_name;
5835
5836 // Get the servers pid_file name and use it to read pid
5837
2/4
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3549 times.
3549 if (query_get_string(mysql, "SHOW VARIABLES LIKE 'pid_file'", 1,
5838 &ds_file_name))
5839 die("Failed to get pid_file from server");
5840
5841 // Read the pid from the file
5842 int fd;
5843 char buff[32];
5844
5845
2/4
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3549 times.
3549 if ((fd = my_open(ds_file_name.c_str(), O_RDONLY, MYF(0))) < 0)
5846 die("Failed to open file '%s'", ds_file_name.c_str());
5847
5848
2/4
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3549 times.
3549 if (my_read(fd, (uchar *)&buff, sizeof(buff), MYF(0)) <= 0) {
5849 my_close(fd, MYF(0));
5850 die("pid file was empty");
5851 }
5852
5853
1/2
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
3549 my_close(fd, MYF(0));
5854
5855 3549 int pid = std::atoi(buff);
5856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3549 times.
3549 if (pid == 0) die("Pidfile didn't contain a valid number");
5857
5858 3549 int error = 0;
5859
2/2
✓ Branch 0 taken 3111 times.
✓ Branch 1 taken 438 times.
3549 if (timeout) {
5860 // Check if we should generate a minidump on timeout.
5861
1/2
✓ Branch 0 taken 3111 times.
✗ Branch 1 not taken.
3111 if (query_get_string(mysql, "SHOW VARIABLES LIKE 'core_file'", 1,
5862
3/4
✓ Branch 0 taken 3111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3083 times.
✓ Branch 3 taken 28 times.
6222 &ds_file_name) ||
5863
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 3083 times.
3111 std::strcmp("ON", ds_file_name.c_str())) {
5864 } else {
5865 // Get the data dir and use it as path for a minidump if needed.
5866
2/4
✓ Branch 0 taken 3083 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3083 times.
3083 if (query_get_string(mysql, "SHOW VARIABLES LIKE 'datadir'", 1,
5867 &ds_file_name))
5868 die("Failed to get datadir from server");
5869 }
5870
5871 3111 const char *var_name = "$MTR_MANUAL_DEBUG";
5872
1/2
✓ Branch 0 taken 3111 times.
✗ Branch 1 not taken.
3111 VAR *var = var_get(var_name, &var_name, false, false);
5873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3111 times.
3111 if (var->int_val) {
5874 if (!kill_process(pid) && is_process_active(pid)) error = 3;
5875 } else {
5876 // Tell server to shutdown if timeout > 0.
5877
4/8
✓ Branch 0 taken 3111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3111 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3111 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3111 times.
3111 if (timeout > 0 && mysql_query_wrapper(mysql, "shutdown")) {
5878 // Failed to issue shutdown command.
5879 error = 1;
5880 3111 goto end;
5881 }
5882
5883 // Check that server dies
5884 do {
5885
3/4
✓ Branch 0 taken 20881 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3111 times.
✓ Branch 3 taken 17770 times.
20881 if (!is_process_active(pid)) {
5886
3/8
✓ Branch 0 taken 3111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3111 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3111 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3111 DBUG_PRINT("info", ("Process %d does not exist anymore", pid));
5887 3111 goto end;
5888 }
5889
1/2
✓ Branch 0 taken 17770 times.
✗ Branch 1 not taken.
17770 if (timeout > 0) {
5890
3/8
✓ Branch 0 taken 17770 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17770 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17770 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
17770 DBUG_PRINT("info", ("Sleeping, timeout: %ld", timeout));
5891
1/2
✓ Branch 0 taken 17770 times.
✗ Branch 1 not taken.
17770 my_sleep(1000000L);
5892 }
5893
1/2
✓ Branch 0 taken 17770 times.
✗ Branch 1 not taken.
17770 } while (timeout-- > 0);
5894
5895 error = 2;
5896
5897 // Abort to make it easier to find the hang/problem.
5898 abort_process(pid, ds_file_name.c_str());
5899 }
5900 } else {
5901 // timeout value is 0, kill the server
5902
3/8
✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 438 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 438 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
438 DBUG_PRINT("info", ("Killing server, pid: %d", pid));
5903
5904 // kill_process can fail (bad privileges, non existing process on
5905 // *nix etc), so also check if the process is active before setting
5906 // error.
5907
3/10
✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 438 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 438 times.
✗ Branch 9 not taken.
438 if (!kill_process(pid) && is_process_active(pid)) error = 3;
5908 }
5909
5910 438 end:
5911
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3549 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3549 if (error) handle_command_error(command, error);
5912 3549 }
5913
5914 /// Evaluate the warning list argument specified with either
5915 /// disable_warnings or enable_warnings command and replace the
5916 /// variables with actual values if there exist any.
5917 ///
5918 /// @param command Pointer to the st_command structure which holds
5919 /// the arguments and information for the command.
5920 /// @param ds_warnings DYNAMIC_STRING object containing the argument.
5921 ///
5922 /// @retval Evaluated string after replacing the variables with values.
5923 1498 const char *eval_warning_argument(struct st_command *command,
5924 DYNAMIC_STRING *ds_warnings) {
5925 1498 dynstr_trunc(ds_warnings, ds_warnings->length);
5926 1498 do_eval(ds_warnings, command->first_argument, command->end, false);
5927 1498 return ds_warnings->str;
5928 }
5929
5930 /// Check if second argument "ONCE" to disable_warnings or enable_warnings
5931 /// command is specified. If yes, filter out the keyword "ONCE" from the
5932 /// argument string.
5933 ///
5934 /// @param ds_property DYNAMIC_STRING object containing the second argument
5935 /// @param warn_argument String to store the argument string containing only
5936 /// the list of warnings.
5937 ///
5938 /// @retval True if the second argument is specified, false otherwise.
5939 1498 static bool check_and_filter_once_property(DYNAMIC_STRING ds_property,
5940 std::string *warn_argument) {
5941
2/2
✓ Branch 0 taken 1257 times.
✓ Branch 1 taken 241 times.
1498 if (ds_property.length) {
5942 // Second argument exists, and it should be "ONCE" keyword.
5943
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1251 times.
1257 if (std::strcmp(ds_property.str, "ONCE"))
5944 6 die("Second argument to '%s' command should always be \"ONCE\" keyword.",
5945 6 command_names[curr_command->type - 1]);
5946
5947 // Filter out the keyword and save only the warnings.
5948 1251 std::size_t position = warn_argument->find(" ONCE");
5949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1251 times.
1251 assert(position != std::string::npos);
5950 1251 warn_argument->erase(position, 5);
5951 1251 return true;
5952 }
5953
5954 241 return false;
5955 }
5956
5957 /// Handle disabling of warnings.
5958 ///
5959 /// * If all warnings are disabled, don't add the warning to disabled
5960 /// warning list.
5961 /// * If there exist enabled warnings, remove the disabled warning from
5962 /// the list of enabled warnings.
5963 /// * If all the warnings are enabled or if there exist disabled warnings,
5964 /// add or append the new warning to the list of disabled warnings.
5965 ///
5966 /// @param warning_code Warning code
5967 /// @param warning Warning string
5968 /// @param once_prop Flag specifying whether a property should be set
5969 /// for next statement only.
5970 1385 static void handle_disable_warnings(std::uint32_t warning_code,
5971 std::string warning, bool once_prop) {
5972
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1370 times.
1385 if (enabled_warnings->count()) {
5973 // Remove the warning from list of enabled warnings.
5974 15 enabled_warnings->remove_warning(warning_code, once_prop);
5975
4/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1355 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1370 times.
✗ Branch 5 not taken.
1370 } else if (!disable_warnings || disabled_warnings->count()) {
5976 // Add the warning to list of expected warnings only if all the
5977 // warnings are not disabled.
5978 1370 disabled_warnings->add_warning(warning_code, warning.c_str(), once_prop);
5979 }
5980 1385 }
5981
5982 /// Handle enabling of warnings.
5983 ///
5984 /// * If all the warnings are enabled, don't add the warning to enabled
5985 /// warning list.
5986 /// * If there exist disabled warnings, remove the enabled warning from
5987 /// the list of disabled warnings.
5988 /// * If all the warnings are disabled or if there exist enabled warnings,
5989 /// add or append the new warning to the list of enabled warnings.
5990 ///
5991 /// @param warning_code Warning code
5992 /// @param warning Warning string
5993 /// @param once_prop Flag specifying whether a property should be set
5994 /// for next statement only.
5995 163 static void handle_enable_warnings(std::uint32_t warning_code,
5996 std::string warning, bool once_prop) {
5997
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 60 times.
163 if (disabled_warnings->count()) {
5998 // Remove the warning from list of disabled warnings.
5999 103 disabled_warnings->remove_warning(warning_code, once_prop);
6000
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 } else if (disabled_warnings) {
6001 // All the warnings are disabled, enable only the warnings specified
6002 // in the argument.
6003 60 enabled_warnings->add_warning(warning_code, warning.c_str(), once_prop);
6004 }
6005 163 }
6006
6007 /// Get an error code corresponding to a warning name. The warning name
6008 /// specified is in symbolic error name format.
6009 ///
6010 /// @param command Pointer to the st_command structure which holds the
6011 /// arguments and information for the command.
6012 /// @param warn_argument String containing warning argument
6013 /// @param once_prop Flag specifying whether a property should be set for
6014 /// next statement only.
6015 1492 static void get_warning_codes(struct st_command *command,
6016 std::string warn_argument, bool once_prop) {
6017 1492 std::string warning;
6018
1/2
✓ Branch 0 taken 1492 times.
✗ Branch 1 not taken.
1492 std::stringstream warnings(warn_argument);
6019
6020
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1486 times.
1492 if (!my_isalnum(charset_info, warn_argument.back())) {
6021 6 die("Invalid argument '%s' to '%s' command.", command->first_argument,
6022 6 command_names[command->type - 1]);
6023 }
6024
6025
4/6
✓ Branch 0 taken 3034 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1566 times.
✓ Branch 5 taken 1468 times.
3034 while (std::getline(warnings, warning, ',')) {
6026 // Remove any space in a string representing a warning.
6027
2/4
✓ Branch 0 taken 1566 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1566 times.
✗ Branch 3 not taken.
1566 warning.erase(remove_if(warning.begin(), warning.end(), isspace),
6028 1566 warning.end());
6029
6030 // Check if a warning name is a valid symbolic error name.
6031
6/6
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1549 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 1554 times.
✓ Branch 5 taken 12 times.
1566 if (warning.front() == 'E' || warning.front() == 'W') {
6032
2/4
✓ Branch 0 taken 1554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1554 times.
✗ Branch 3 not taken.
1554 int warning_code = get_errcode_from_name(warning);
6033
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1548 times.
1554 if (warning_code == -1)
6034 6 die("Unknown SQL error name '%s'.", warning.c_str());
6035
2/2
✓ Branch 0 taken 1385 times.
✓ Branch 1 taken 163 times.
1548 if (command->type == Q_DISABLE_WARNINGS)
6036
2/4
✓ Branch 0 taken 1385 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1385 times.
✗ Branch 3 not taken.
1385 handle_disable_warnings(warning_code, warning, once_prop);
6037
1/2
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
163 else if (command->type == Q_ENABLE_WARNINGS) {
6038
2/4
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163 times.
✗ Branch 3 not taken.
163 handle_enable_warnings(warning_code, warning, once_prop);
6039 // If disable_warnings flag is set, and there are no disabled or
6040 // enabled warnings, set the disable_warnings flag to 0.
6041
1/2
✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
163 if (disable_warnings) {
6042
6/6
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 77 times.
✓ Branch 5 taken 86 times.
163 if (!disabled_warnings->count() && !enabled_warnings->count())
6043
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 set_property(command, P_WARN, false);
6044 }
6045 }
6046 } else {
6047 // Invalid argument, should only consist of warnings specified in
6048 // symbolic error name format.
6049 12 die("Invalid argument '%s' to '%s' command, list of disabled or enabled "
6050 "warnings may only consist of symbolic error names.",
6051 12 command->first_argument, command_names[command->type - 1]);
6052 }
6053 }
6054 1468 }
6055
6056 /// Parse the warning list argument specified with disable_warnings or
6057 /// enable_warnings command. Check if the second argument "ONCE" is
6058 /// specified, if yes, set once_property flag.
6059 ///
6060 /// @param command Pointer to the st_command structure which holds the
6061 /// arguments and information for the command.
6062 ///
6063 /// @retval True if second argument "ONCE" is specified, false otherwise.
6064 1507 static bool parse_warning_list_argument(struct st_command *command) {
6065 DYNAMIC_STRING ds_warnings, ds_property;
6066 1507 const struct command_arg warning_args[] = {
6067 {"Warnings", ARG_STRING, false, &ds_warnings,
6068 "Comma separated list of warnings to be disabled or enabled."},
6069 {"Property", ARG_STRING, false, &ds_property,
6070 "Keyword \"ONCE\" repesenting the property should be set for next "
6071 1507 "statement only."}};
6072
6073
1/2
✓ Branch 0 taken 1507 times.
✗ Branch 1 not taken.
1507 check_command_args(command, command->first_argument, warning_args,
6074 sizeof(warning_args) / sizeof(struct command_arg), ' ');
6075
6076 // Waning list argument can't be an empty string.
6077
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1498 times.
1507 if (!ds_warnings.length)
6078 9 die("Warning list argument to command '%s' can't be an empty string.",
6079 9 command_names[command->type - 1]);
6080
6081 // Evaluate warning list argument and replace the variables with
6082 // actual values
6083
2/4
✓ Branch 0 taken 1498 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1498 times.
✗ Branch 3 not taken.
1498 std::string warn_argument = eval_warning_argument(command, &ds_warnings);
6084
6085 // Set once_prop flag to true if keyword "ONCE" is specified as an
6086 // argument to a disable_warnings or a enable_warnings command.
6087 // Filter this keyword from the argument string and save only the
6088 // list of warnings.
6089
1/2
✓ Branch 0 taken 1492 times.
✗ Branch 1 not taken.
1498 bool once_prop = check_and_filter_once_property(ds_property, &warn_argument);
6090
6091 // Free all the DYNAMIC_STRING objects created
6092
1/2
✓ Branch 0 taken 1492 times.
✗ Branch 1 not taken.
1492 free_dynamic_strings(&ds_warnings, &ds_property);
6093
6094 // Get warning codes
6095
2/4
✓ Branch 0 taken 1492 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1468 times.
✗ Branch 3 not taken.
1492 get_warning_codes(command, warn_argument, once_prop);
6096
6097 1468 return once_prop;
6098 1468 }
6099
6100 /// Create a list of disabled warnings that should be suppressed for
6101 /// the next statements until enabled by enable_warnings command.
6102 ///
6103 /// disable_warnings command can take an optional argument specifying
6104 /// a warning or a comma separated list of warnings to be disabled.
6105 /// The warnings specified should be in symbolic error name format.
6106 ///
6107 /// disable_warnings command can also take a second optional argument,
6108 /// which when specified will suppress the warnings for next statement
6109 /// only. The second argument must be a "ONCE" keyword.
6110 ///
6111 /// @param command Pointer to the st_command structure which holds the
6112 /// arguments and information for the command.
6113 39323 static void do_disable_warnings(struct st_command *command) {
6114 // Revert the previously set properties
6115
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 39320 times.
39323 if (once_property) revert_properties();
6116
6117 // Check if disable_warnings command has warning list argument.
6118
2/2
✓ Branch 0 taken 37971 times.
✓ Branch 1 taken 1352 times.
39323 if (!*command->first_argument) {
6119 // disable_warnings without an argument, disable all the warnings.
6120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37971 times.
37971 if (disabled_warnings->count()) disabled_warnings->clear_list();
6121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37971 times.
37971 if (enabled_warnings->count()) enabled_warnings->clear_list();
6122
6123 // Update the environment variables containing the list of disabled
6124 // and enabled warnings.
6125 37971 update_disabled_enabled_warnings_list_var();
6126
6127 // Set 'disable_warnings' property value to 1
6128 37971 set_property(command, P_WARN, true);
6129 37971 return;
6130 } else {
6131 // Parse the warning list argument specified with disable_warnings
6132 // command.
6133 1352 parse_warning_list_argument(command);
6134
6135 // Update the environment variables containing the list of disabled
6136 // and enabled warnings.
6137 1334 update_disabled_enabled_warnings_list_var();
6138
6139 // Set 'disable_warnings' property value to 1
6140 1334 set_property(command, P_WARN, true);
6141 }
6142
6143 1334 command->last_argument = command->end;
6144 }
6145
6146 /// Create a list of enabled warnings that should be enabled for the
6147 /// next statements until disabled by disable_warnings command.
6148 ///
6149 /// enable_warnings command can take an optional argument specifying
6150 /// a warning or a comma separated list of warnings to be enabled. The
6151 /// warnings specified should be in symbolic error name format.
6152 ///
6153 /// enable_warnings command can also take a second optional argument,
6154 /// which when specified will enable the warnings for next statement
6155 /// only. The second argument must be a "ONCE" keyword.
6156 ///
6157 /// @param command Pointer to the st_command structure which holds the
6158 /// arguments and information for the command.
6159 31554 static void do_enable_warnings(struct st_command *command) {
6160 // Revert the previously set properties
6161
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 31551 times.
31554 if (once_property) revert_properties();
6162
6163 31554 bool once_prop = false;
6164
2/2
✓ Branch 0 taken 31399 times.
✓ Branch 1 taken 155 times.
31554 if (!*command->first_argument) {
6165 // enable_warnings without an argument, enable all the warnings.
6166
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 31396 times.
31399 if (disabled_warnings->count()) disabled_warnings->clear_list();
6167
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 31390 times.
31399 if (enabled_warnings->count()) enabled_warnings->clear_list();
6168
6169 // Update the environment variables containing the list of disabled
6170 // and enabled warnings.
6171 31399 update_disabled_enabled_warnings_list_var();
6172
6173 // Set 'disable_warnings' property value to 0
6174 31399 set_property(command, P_WARN, false);
6175 } else {
6176 // Parse the warning list argument specified with enable_warnings command.
6177 155 once_prop = parse_warning_list_argument(command);
6178
6179 // Update the environment variables containing the list of disabled and
6180 // enabled warnings.
6181 134 update_disabled_enabled_warnings_list_var();
6182 }
6183
6184 // Call set_once_property() to set once_propetry flag.
6185
4/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 31476 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 36 times.
31533 if (disable_warnings && once_prop) set_once_property(P_WARN, true);
6186
6187 31533 command->last_argument = command->end;
6188 31533 }
6189
6190 /// Create a list of error values that the next statement is expected
6191 /// to return. Each error must be an error number or an SQLSTATE value
6192 /// or a symbolic error name representing an error.
6193 ///
6194 /// SQLSTATE value must start with 'S'. It is also possible to specify
6195 /// client errors with 'error' command.
6196 ///
6197 /// @code
6198 /// --error 1064
6199 /// --error S42S01
6200 /// --error ER_TABLE_EXISTS_ERROR,ER_PARSE_ERROR
6201 /// --error CR_SERVER_GONE_ERROR
6202 /// @endcode
6203 ///
6204 /// @param command Pointer to the st_command structure which holds the
6205 /// arguments and information for the command.
6206 666431 static void do_error(struct st_command *command) {
6207
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666425 times.
666431 if (!*command->first_argument) die("Missing argument(s) to 'error' command.");
6208
6209 // Check if error command ends with a comment
6210 666425 char *end = command->first_argument + std::strlen(command->first_argument);
6211
2/2
✓ Branch 0 taken 63899904 times.
✓ Branch 1 taken 666404 times.
64566308 while (std::strlen(command->first_argument) > std::strlen(end)) {
6212 63899904 end--;
6213
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 63899883 times.
63899904 if (*end == '#') break;
6214 }
6215
6216
2/2
✓ Branch 0 taken 666404 times.
✓ Branch 1 taken 21 times.
666425 if (std::strlen(command->first_argument) == std::strlen(end))
6217 666404 end = command->first_argument + std::strlen(command->first_argument);
6218
6219 666425 std::string error;
6220
2/4
✓ Branch 0 taken 666425 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666425 times.
✗ Branch 3 not taken.
1332850 std::stringstream errors(std::string(command->first_argument, end));
6221
6222 // Get error codes
6223
4/6
✓ Branch 0 taken 6920166 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6920166 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6253774 times.
✓ Branch 5 taken 666392 times.
6920166 while (std::getline(errors, error, ',')) {
6224 // Remove any space from the string representing an error.
6225
2/4
✓ Branch 0 taken 6253774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6253774 times.
✗ Branch 3 not taken.
6253774 error.erase(remove_if(error.begin(), error.end(), isspace), error.end());
6226
6227 // Code to handle a variable containing an error.
6228
2/2
✓ Branch 0 taken 3925 times.
✓ Branch 1 taken 6249849 times.
6253774 if (error.front() == '$') {
6229 3925 const char *varname_end = nullptr;
6230
1/2
✓ Branch 0 taken 3925 times.
✗ Branch 1 not taken.
3925 VAR *var = var_get(error.c_str(), &varname_end, false, false);
6231
1/2
✓ Branch 0 taken 3925 times.
✗ Branch 1 not taken.
3925 error.assign(var->str_val);
6232 }
6233
6234
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 6253723 times.
6253774 if (error.front() == 'S') {
6235 // SQLSTATE string
6236 // * Must be SQLSTATE_LENGTH long
6237 // * May contain only digits[0-9] and _uppercase_ letters
6238
6239 // Step pass 'S' character
6240
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
51 error = error.substr(1, error.length());
6241
6242
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 45 times.
51 if (error.length() != SQLSTATE_LENGTH)
6243 6 die("The sqlstate must be exactly %d chars long.", SQLSTATE_LENGTH);
6244
6245 // Check the validity of an SQLSTATE string.
6246
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 42 times.
261 for (std::size_t i = 0; i < error.length(); i++) {
6247
5/6
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 210 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 216 times.
228 if (!my_isdigit(charset_info, error[i]) &&
6248
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
9 !my_isupper(charset_info, error[i]))
6249 3 die("The sqlstate may only consist of digits[0-9] and _uppercase_ "
6250 "letters.");
6251 }
6252
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 expected_errors->add_error(error.c_str(), ERR_SQLSTATE);
6253
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6253720 times.
6253723 } else if (error.front() == 's') {
6254 3 die("The sqlstate definition must start with an uppercase S.");
6255 }
6256 // Checking for both server error names as well as client error names.
6257
6/6
✓ Branch 0 taken 6252633 times.
✓ Branch 1 taken 1087 times.
✓ Branch 2 taken 1671415 times.
✓ Branch 3 taken 4581218 times.
✓ Branch 4 taken 1672502 times.
✓ Branch 5 taken 4581218 times.
6253720 else if (error.front() == 'C' || error.front() == 'E') {
6258 // Code to handle --error <error_string>.
6259
2/4
✓ Branch 0 taken 1672502 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1672502 times.
✗ Branch 3 not taken.
1672502 int error_code = get_errcode_from_name(error);
6260
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1672499 times.
1672502 if (error_code == -1) die("Unknown SQL error name '%s'.", error.c_str());
6261
1/2
✓ Branch 0 taken 1672499 times.
✗ Branch 1 not taken.
1672499 expected_errors->add_error(error_code, ERR_ERRNO);
6262
5/6
✓ Branch 0 taken 4581218 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4581215 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 4581215 times.
4581218 } else if (error.front() == 'c' || error.front() == 'e') {
6263 3 die("The error name definition must start with an uppercase C or E.");
6264 } else {
6265 // Check that the string passed to error command contains only digits.
6266
1/2
✓ Branch 0 taken 4581215 times.
✗ Branch 1 not taken.
4581215 int error_code = get_int_val(error.c_str());
6267
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4581203 times.
4581215 if (error_code == -1)
6268 12 die("Invalid argument '%s' to 'error' command, the argument may "
6269 "consist of either symbolic error names or error codes.",
6270 command->first_argument);
6271
1/2
✓ Branch 0 taken 4581203 times.
✗ Branch 1 not taken.
4581203 expected_errors->add_error((std::uint32_t)error_code, ERR_ERRNO);
6272 }
6273
6274
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6253741 times.
6253744 if (expected_errors->count() >= MAX_ERROR_COUNT)
6275 3 die("Too many errorcodes specified.");
6276 }
6277
6278 666392 command->last_argument = command->end;
6279 666392 }
6280
6281 /*
6282 Get a string; Return ptr to end of string
6283 Strings may be surrounded by " or '
6284
6285 If string is a '$variable', return the value of the variable.
6286 */
6287
6288 372165 static char *get_string(char **to_ptr, const char **from_ptr,
6289 struct st_command *command) {
6290 char c, sep;
6291 372165 char *to = *to_ptr, *start = to;
6292 372165 const char *from = *from_ptr;
6293
1/2
✓ Branch 0 taken 372165 times.
✗ Branch 1 not taken.
372165 DBUG_TRACE;
6294
6295 /* Find separator */
6296
4/4
✓ Branch 0 taken 340182 times.
✓ Branch 1 taken 31983 times.
✓ Branch 2 taken 1329 times.
✓ Branch 3 taken 338853 times.
372165 if (*from == '"' || *from == '\'')
6297 33312 sep = *from++;
6298 else
6299 338853 sep = ' '; /* Separated with space */
6300
6301
2/2
✓ Branch 0 taken 1741887 times.
✓ Branch 1 taken 28301 times.
1770188 for (; (c = *from); from++) {
6302
3/4
✓ Branch 0 taken 794 times.
✓ Branch 1 taken 1741093 times.
✓ Branch 2 taken 794 times.
✗ Branch 3 not taken.
1741887 if (c == '\\' && from[1]) { /* Escaped character */
6303 /* We can't translate \0 -> ASCII 0 as replace can't handle ASCII 0 */
6304
3/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 606 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 186 times.
794 switch (*++from) {
6305 2 case 'n':
6306 2 *to++ = '\n';
6307 2 break;
6308 case 't':
6309 *to++ = '\t';
6310 break;
6311 606 case 'r':
6312 606 *to++ = '\r';
6313 606 break;
6314 case 'b':
6315 *to++ = '\b';
6316 break;
6317 case 'Z': /* ^Z must be escaped on Win32 */
6318 *to++ = '\032';
6319 break;
6320 186 default:
6321 186 *to++ = *from;
6322 186 break;
6323 }
6324
2/2
✓ Branch 0 taken 343864 times.
✓ Branch 1 taken 1397229 times.
1741093 } else if (c == sep) {
6325
4/6
✓ Branch 0 taken 33312 times.
✓ Branch 1 taken 310552 times.
✓ Branch 2 taken 33312 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 343864 times.
✗ Branch 5 not taken.
343864 if (c == ' ' || c != *++from) break; /* Found end of string */
6326 *to++ = c; /* Copy duplicated separator */
6327 } else
6328 1397229 *to++ = c;
6329 }
6330
3/4
✓ Branch 0 taken 44798 times.
✓ Branch 1 taken 327367 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 44798 times.
372165 if (*from != ' ' && *from) die("Wrong string argument in %s", command->query);
6331
6332
2/2
✓ Branch 0 taken 328634 times.
✓ Branch 1 taken 372165 times.
700799 while (my_isspace(charset_info, *from)) /* Point to next string */
6333 328634 from++;
6334
6335 372165 *to = 0; /* End of string marker */
6336 372165 *to_ptr = to + 1; /* Store pointer to end */
6337 372165 *from_ptr = from;
6338
6339 /* Check if this was a variable */
6340
2/2
✓ Branch 0 taken 38288 times.
✓ Branch 1 taken 333877 times.
372165 if (*start == '$') {
6341 38288 const char *end = to;
6342
1/2
✓ Branch 0 taken 38288 times.
✗ Branch 1 not taken.
38288 VAR *var = var_get(start, &end, false, true);
6343
3/4
✓ Branch 0 taken 38288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38055 times.
✓ Branch 3 taken 233 times.
38288 if (var && to == end + 1) {
6344
3/8
✓ Branch 0 taken 38055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38055 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 38055 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
38055 DBUG_PRINT("info", ("var: '%s' -> '%s'", start, var->str_val));
6345 38055 return var->str_val; /* return found variable value */
6346 }
6347 }
6348 334110 return start;
6349 372165 }
6350
6351 21477 static void set_reconnect(MYSQL *mysql, int val) {
6352 21477 bool reconnect = val;
6353
1/2
✓ Branch 0 taken 21477 times.
✗ Branch 1 not taken.
21477 DBUG_TRACE;
6354
3/8
✓ Branch 0 taken 21477 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21477 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 21477 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
21477 DBUG_PRINT("info", ("val: %d", val));
6355
1/2
✓ Branch 0 taken 21477 times.
✗ Branch 1 not taken.
21477 mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect);
6356 21477 }
6357
6358 /**
6359 Change the current connection to the given st_connection, and update
6360 $mysql_get_server_version and $CURRENT_CONNECTION accordingly.
6361 */
6362 1122478 static void set_current_connection(struct st_connection *con) {
6363 1122478 cur_con = con;
6364 /* Update $mysql_get_server_version to that of current connection */
6365 1122478 var_set_int("$mysql_get_server_version",
6366 1122478 mysql_get_server_version(&con->mysql));
6367 /* Update $CURRENT_CONNECTION to the name of the current connection */
6368 1122478 var_set_string("$CURRENT_CONNECTION", con->name);
6369 1122478 }
6370
6371 1026826 static void select_connection_name(const char *name) {
6372
1/2
✓ Branch 0 taken 1026826 times.
✗ Branch 1 not taken.
1026826 DBUG_TRACE;
6373
3/8
✓ Branch 0 taken 1026826 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1026826 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1026826 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1026826 DBUG_PRINT("enter", ("name: '%s'", name));
6374 1026826 st_connection *con = find_connection_by_name(name);
6375
6376
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1026823 times.
1026826 if (!con) die("connection '%s' not found in connection pool", name);
6377
6378
1/2
✓ Branch 0 taken 1026823 times.
✗ Branch 1 not taken.
1026823 set_current_connection(con);
6379
6380 /* Connection logging if enabled */
6381
4/4
✓ Branch 0 taken 3533 times.
✓ Branch 1 taken 1023290 times.
✓ Branch 2 taken 3493 times.
✓ Branch 3 taken 40 times.
1026823 if (!disable_connect_log && !disable_query_log) {
6382 3493 DYNAMIC_STRING *ds = &ds_res;
6383
6384
1/2
✓ Branch 0 taken 3493 times.
✗ Branch 1 not taken.
3493 dynstr_append_mem(ds, "connection ", 11);
6385
1/2
✓ Branch 0 taken 3493 times.
✗ Branch 1 not taken.
3493 replace_dynstr_append(ds, name);
6386
1/2
✓ Branch 0 taken 3493 times.
✗ Branch 1 not taken.
3493 dynstr_append_mem(ds, ";\n", 2);
6387 }
6388 1026823 }
6389
6390 1025307 static void select_connection(struct st_command *command) {
6391
1/2
✓ Branch 0 taken 1025307 times.
✗ Branch 1 not taken.
1025307 DBUG_TRACE;
6392 static DYNAMIC_STRING ds_connection;
6393 1025307 const struct command_arg connection_args[] = {
6394 {"connection_name", ARG_STRING, true, &ds_connection,
6395 "Name of the connection that we switch to."}};
6396
1/2
✓ Branch 0 taken 1025307 times.
✗ Branch 1 not taken.
1025307 check_command_args(command, command->first_argument, connection_args,
6397 sizeof(connection_args) / sizeof(struct command_arg), ' ');
6398
6399
3/8
✓ Branch 0 taken 1025307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1025307 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1025307 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1025307 DBUG_PRINT("info", ("changing connection: %s", ds_connection.str));
6400
1/2
✓ Branch 0 taken 1025304 times.
✗ Branch 1 not taken.
1025307 select_connection_name(ds_connection.str);
6401
1/2
✓ Branch 0 taken 1025304 times.
✗ Branch 1 not taken.
1025304 dynstr_free(&ds_connection);
6402 1025304 }
6403
6404 31435 static void do_close_connection(struct st_command *command) {
6405
1/2
✓ Branch 0 taken 31435 times.
✗ Branch 1 not taken.
31435 DBUG_TRACE;
6406
6407 struct st_connection *con;
6408 static DYNAMIC_STRING ds_connection;
6409 31435 const struct command_arg close_connection_args[] = {
6410 {"connection_name", ARG_STRING, true, &ds_connection,
6411 "Name of the connection to close."}};
6412
1/2
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
31435 check_command_args(command, command->first_argument, close_connection_args,
6413 sizeof(close_connection_args) / sizeof(struct command_arg),
6414 ' ');
6415
6416
3/8
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31429 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31429 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
31429 DBUG_PRINT("enter", ("connection name: '%s'", ds_connection.str));
6417
6418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31429 times.
31429 if (!(con = find_connection_by_name(ds_connection.str)))
6419 die("connection '%s' not found in connection pool", ds_connection.str);
6420
6421
3/8
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31429 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31429 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
31429 DBUG_PRINT("info", ("Closing connection %s", con->name));
6422
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 31421 times.
31429 if (command->type == Q_DIRTY_CLOSE) {
6423
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (con->mysql.net.vio) {
6424
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 vio_delete(con->mysql.net.vio);
6425 8 con->mysql.net.vio = nullptr;
6426
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 end_server(&con->mysql);
6427 }
6428 }
6429
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 31429 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
31429 if (con->stmt) mysql_stmt_close(con->stmt);
6430 31429 con->stmt = nullptr;
6431
6432
1/2
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
31429 mysql_close(&con->mysql);
6433
6434
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 31429 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
31429 if (con->util_mysql) mysql_close(con->util_mysql);
6435 31429 con->util_mysql = nullptr;
6436 31429 con->pending = false;
6437
6438
1/2
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
31429 my_free(con->name);
6439
6440 /*
6441 When the connection is closed set name to "-closed_connection-"
6442 to make it possible to reuse the connection name.
6443 */
6444
2/4
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31429 times.
31429 if (!(con->name = my_strdup(PSI_NOT_INSTRUMENTED, "-closed_connection-",
6445 MYF(MY_WME))))
6446 die("Out of memory");
6447
6448
2/2
✓ Branch 0 taken 6508 times.
✓ Branch 1 taken 24921 times.
31429 if (con == cur_con) {
6449 /* Current connection was closed */
6450
1/2
✓ Branch 0 taken 6508 times.
✗ Branch 1 not taken.
6508 var_set_int("$mysql_get_server_version", 0xFFFFFFFF);
6451
1/2
✓ Branch 0 taken 6508 times.
✗ Branch 1 not taken.
6508 var_set_string("$CURRENT_CONNECTION", con->name);
6452 }
6453
6454 /* Connection logging if enabled */
6455
4/4
✓ Branch 0 taken 788 times.
✓ Branch 1 taken 30641 times.
✓ Branch 2 taken 785 times.
✓ Branch 3 taken 3 times.
31429 if (!disable_connect_log && !disable_query_log) {
6456 785 DYNAMIC_STRING *ds = &ds_res;
6457
6458
1/2
✓ Branch 0 taken 785 times.
✗ Branch 1 not taken.
785 dynstr_append_mem(ds, "disconnect ", 11);
6459
1/2
✓ Branch 0 taken 785 times.
✗ Branch 1 not taken.
785 replace_dynstr_append(ds, ds_connection.str);
6460
1/2
✓ Branch 0 taken 785 times.
✗ Branch 1 not taken.
785 dynstr_append_mem(ds, ";\n", 2);
6461 }
6462
6463
1/2
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
31429 dynstr_free(&ds_connection);
6464 31429 }
6465
6466 /*
6467 Connect to a server doing several retries if needed.
6468
6469 SYNOPSIS
6470 safe_connect()
6471 con - connection structure to be used
6472 host, user, pass, - connection parameters
6473 db, port, sock
6474
6475 NOTE
6476
6477 Sometimes in a test the client starts before
6478 the server - to solve the problem, we try again
6479 after some sleep if connection fails the first
6480 time
6481
6482 This function will try to connect to the given server
6483 "opt_max_connect_retries" times and sleep "connection_retry_sleep"
6484 seconds between attempts before finally giving up.
6485 This helps in situation when the client starts
6486 before the server (which happens sometimes).
6487 It will only ignore connection errors during these retries.
6488
6489 */
6490
6491 50111 static void safe_connect(MYSQL *mysql, const char *name, const char *host,
6492 const char *user, const char *pass, const char *db,
6493 int port, const char *sock) {
6494 50111 int failed_attempts = 0;
6495
6496
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 DBUG_TRACE;
6497
6498
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 verbose_msg(
6499 "Connecting to server %s:%d (socket %s) as '%s'"
6500 ", connection '%s', attempt %d ...",
6501 host, port, sock, user, name, failed_attempts);
6502
6503
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, nullptr);
6504
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name",
6505 "mysqltest");
6506
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 mysql_options(mysql, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
6507 &can_handle_expired_passwords);
6508
3/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 50105 times.
50111 while (!mysql_real_connect_wrapper(
6509 mysql, host, user, pass, db, port, sock,
6510 CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS)) {
6511 /*
6512 Connect failed
6513
6514 Only allow retry if this was an error indicating the server
6515 could not be contacted. Error code differs depending
6516 on protocol/connection type
6517 */
6518
6519
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if ((mysql_errno(mysql) == CR_CONN_HOST_ERROR ||
6520
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 mysql_errno(mysql) == CR_CONNECTION_ERROR ||
6521
4/8
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
12 mysql_errno(mysql) == CR_NAMEDPIPEOPEN_ERROR) &&
6522 failed_attempts < opt_max_connect_retries) {
6523 verbose_msg("Connect attempt %d/%d failed: %d: %s", failed_attempts,
6524 opt_max_connect_retries, mysql_errno(mysql),
6525 mysql_error(mysql));
6526 my_sleep(connection_retry_sleep);
6527 } else {
6528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (failed_attempts > 0)
6529 die("Could not open connection '%s' after %d attempts: %d %s", name,
6530 failed_attempts, mysql_errno(mysql), mysql_error(mysql));
6531 else
6532
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 die("Could not open connection '%s': %d %s", name, mysql_errno(mysql),
6533 mysql_error(mysql));
6534 }
6535 failed_attempts++;
6536 }
6537
1/2
✓ Branch 0 taken 50105 times.
✗ Branch 1 not taken.
50105 verbose_msg("... Connected.");
6538 50105 }
6539
6540 /// Connect to a server and handle connection errors in case they
6541 /// occur.
6542 ///
6543 /// This function will try to establish a connection to server and
6544 /// handle possible errors in the same manner as if "connect" was usual
6545 /// SQL-statement. If an error is expected it will ignore it once it
6546 /// occurs and log the "statement" to the query log. Unlike
6547 /// safe_connect() it won't do several attempts.
6548 ///
6549 /// @param command Pointer to the st_command structure which holds the
6550 /// arguments and information for the command.
6551 /// @param con Connection structure to be used
6552 /// @param host Host name
6553 /// @param user User name
6554 /// @param pass Password
6555 /// @param db Database name
6556 /// @param port Port number
6557 /// @param sock Socket value
6558 ///
6559 /// @retval 1 if connection succeeds, 0 otherwise
6560 46240 static int connect_n_handle_errors(struct st_command *command, MYSQL *con,
6561 const char *host, const char *user,
6562 const char *pass, const char *db, int port,
6563 const char *sock) {
6564 DYNAMIC_STRING *ds;
6565 46240 int failed_attempts = 0;
6566
6567 46240 ds = &ds_res;
6568
6569 /* Only log if an error is expected */
6570
6/6
✓ Branch 0 taken 583 times.
✓ Branch 1 taken 45657 times.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 346 times.
✓ Branch 4 taken 237 times.
✓ Branch 5 taken 46003 times.
46240 if (expected_errors->count() > 0 && !disable_query_log) {
6571 /*
6572 Log the connect to result log
6573 */
6574 237 dynstr_append_mem(ds, "connect(", 8);
6575 237 replace_dynstr_append(ds, host);
6576 237 dynstr_append_mem(ds, ",", 1);
6577 237 replace_dynstr_append(ds, user);
6578 237 dynstr_append_mem(ds, ",", 1);
6579 237 replace_dynstr_append(ds, pass);
6580 237 dynstr_append_mem(ds, ",", 1);
6581
1/2
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
237 if (db) replace_dynstr_append(ds, db);
6582 237 dynstr_append_mem(ds, ",", 1);
6583 237 replace_dynstr_append_uint(ds, port);
6584 237 dynstr_append_mem(ds, ",", 1);
6585
1/2
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
237 if (sock) replace_dynstr_append(ds, sock);
6586 237 dynstr_append_mem(ds, ")", 1);
6587 237 dynstr_append_mem(ds, delimiter, delimiter_length);
6588 237 dynstr_append_mem(ds, "\n", 1);
6589 }
6590 /* Simplified logging if enabled */
6591
4/4
✓ Branch 0 taken 809 times.
✓ Branch 1 taken 45431 times.
✓ Branch 2 taken 806 times.
✓ Branch 3 taken 3 times.
46240 if (!disable_connect_log && !disable_query_log) {
6592 806 replace_dynstr_append(ds, command->query);
6593 806 dynstr_append_mem(ds, ";\n", 2);
6594 }
6595
6596 46240 mysql_options(con, MYSQL_OPT_CONNECT_ATTR_RESET, nullptr);
6597 46240 mysql_options4(con, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", "mysqltest");
6598 46240 mysql_options(con, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
6599 &can_handle_expired_passwords);
6600
2/2
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 45552 times.
46240 while (!mysql_real_connect_wrapper(con, host, user, pass, db, port,
6601 sock ? sock : nullptr,
6602 CLIENT_MULTI_STATEMENTS)) {
6603 /*
6604 If we have used up all our connections check whether this
6605 is expected (by --error). If so, handle the error right away.
6606 Otherwise, give it some extra time to rule out race-conditions.
6607 If extra-time doesn't help, we have an unexpected error and
6608 must abort -- just proceeding to handle_error() when second
6609 and third chances are used up will handle that for us.
6610
6611 There are various user-limits of which only max_user_connections
6612 and max_connections_per_hour apply at connect time. For the
6613 the second to create a race in our logic, we'd need a limits
6614 test that runs without a FLUSH for longer than an hour, so we'll
6615 stay clear of trying to work out which exact user-limit was
6616 exceeded.
6617 */
6618
6619 688 if (((mysql_errno(con) == ER_TOO_MANY_USER_CONNECTIONS) ||
6620
6/6
✓ Branch 0 taken 682 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 669 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 669 times.
707 (mysql_errno(con) == ER_USER_LIMIT_REACHED)) &&
6621
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 (failed_attempts++ < opt_max_connect_retries)) {
6622 int i;
6623
6624 19 i = match_expected_error(command, mysql_errno(con), mysql_sqlstate(con));
6625
6626
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if (i >= 0) goto do_handle_error; /* expected error, handle */
6627
6628 my_sleep(connection_retry_sleep); /* unexpected error, wait */
6629 continue; /* and give it 1 more chance */
6630 }
6631
6632 669 do_handle_error:
6633 688 var_set_errno(mysql_errno(con));
6634 688 handle_error(command, mysql_errno(con), mysql_error(con),
6635 mysql_sqlstate(con), ds);
6636 685 return 0; /* Not connected */
6637 }
6638
6639 45552 var_set_errno(0);
6640 45552 handle_no_error(command);
6641 45552 revert_properties();
6642 45552 return 1; /* Connected */
6643 }
6644
6645 /*
6646 Open a new connection to MySQL Server with the parameters
6647 specified. Make the new connection the current connection.
6648
6649 SYNOPSIS
6650 do_connect()
6651 q called command
6652
6653 DESCRIPTION
6654 connect(<name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]]);
6655 connect <name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]];
6656
6657 <name> - name of the new connection
6658 <host> - hostname of server
6659 <user> - user to connect as
6660 <pass> - password used when connecting
6661 <db> - initial db when connected
6662 <port> - server port
6663 <sock> - server socket
6664 <opts> - options to use for the connection
6665 * SSL - use SSL if available
6666 * COMPRESS - use compression if available
6667 * SHM - use shared memory if available
6668 * PIPE - use named pipe if available
6669 * SOCKET - use socket protocol
6670 * TCP - use tcp protocol
6671 */
6672
6673 46267 static void do_connect(struct st_command *command) {
6674 46267 int con_port = opt_port;
6675 char *con_options;
6676 46267 bool con_ssl = false, con_compress = false;
6677 46267 bool con_pipe = false, con_shm = false, con_cleartext_enable = false;
6678 struct st_connection *con_slot;
6679 46267 uint save_opt_ssl_mode = opt_ssl_mode;
6680
6681 static DYNAMIC_STRING ds_connection_name;
6682 static DYNAMIC_STRING ds_host;
6683 static DYNAMIC_STRING ds_user;
6684 static DYNAMIC_STRING ds_password1;
6685 static DYNAMIC_STRING ds_database;
6686 static DYNAMIC_STRING ds_port;
6687 static DYNAMIC_STRING ds_sock;
6688 static DYNAMIC_STRING ds_options;
6689 static DYNAMIC_STRING ds_default_auth;
6690 static DYNAMIC_STRING ds_shm;
6691 static DYNAMIC_STRING ds_compression_algorithm;
6692 static DYNAMIC_STRING ds_zstd_compression_level;
6693 static DYNAMIC_STRING ds_password2;
6694 static DYNAMIC_STRING ds_password3;
6695 46267 const struct command_arg connect_args[] = {
6696 {"connection name", ARG_STRING, true, &ds_connection_name,
6697 "Name of the connection"},
6698 {"host", ARG_STRING, true, &ds_host, "Host to connect to"},
6699 {"user", ARG_STRING, false, &ds_user, "User to connect as"},
6700 {"passsword", ARG_STRING, false, &ds_password1,
6701 "Password used when connecting"},
6702 {"database", ARG_STRING, false, &ds_database,
6703 "Database to select after connect"},
6704 {"port", ARG_STRING, false, &ds_port, "Port to connect to"},
6705 {"socket", ARG_STRING, false, &ds_sock, "Socket to connect with"},
6706 {"options", ARG_STRING, false, &ds_options,
6707 "Options to use while connecting"},
6708 {"default_auth", ARG_STRING, false, &ds_default_auth,
6709 "Default authentication to use"},
6710 {"default_compression_algorithm", ARG_STRING, false,
6711 &ds_compression_algorithm, "Default compression algorithm to use"},
6712 {"default_zstd_compression_level", ARG_STRING, false,
6713 &ds_zstd_compression_level,
6714 "Default compression level to use "
6715 "when using zstd compression."},
6716 {"second_passsword", ARG_STRING, false, &ds_password2,
6717 "Password used when connecting"},
6718 {"third_passsword", ARG_STRING, false, &ds_password3,
6719 "Password used when connecting"}};
6720
6721
1/2
✓ Branch 0 taken 46267 times.
✗ Branch 1 not taken.
46267 DBUG_TRACE;
6722
3/8
✓ Branch 0 taken 46267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46267 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 46267 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
46267 DBUG_PRINT("enter", ("connect: %s", command->first_argument));
6723
6724
1/2
✓ Branch 0 taken 46267 times.
✗ Branch 1 not taken.
46267 strip_parentheses(command);
6725
1/2
✓ Branch 0 taken 46255 times.
✗ Branch 1 not taken.
46267 check_command_args(command, command->first_argument, connect_args,
6726 sizeof(connect_args) / sizeof(struct command_arg), ',');
6727
6728 /* Port */
6729
2/2
✓ Branch 0 taken 32347 times.
✓ Branch 1 taken 13908 times.
46255 if (ds_port.length) {
6730 32347 con_port = atoi(ds_port.str);
6731
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 32344 times.
32347 if (con_port == 0) die("Illegal argument for port: '%s'", ds_port.str);
6732 }
6733
6734 /* Shared memory */
6735
1/2
✓ Branch 0 taken 46252 times.
✗ Branch 1 not taken.
46252 init_dynamic_string(&ds_shm, ds_sock.str, 0);
6736
6737 /* Sock */
6738
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 46051 times.
46252 if (ds_sock.length) {
6739 /*
6740 If the socket is specified just as a name without path
6741 append tmpdir in front
6742 */
6743
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 193 times.
201 if (*ds_sock.str != FN_LIBCHAR) {
6744 char buff[FN_REFLEN];
6745
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 fn_format(buff, ds_sock.str, TMPDIR, "", 0);
6746
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 dynstr_set(&ds_sock, buff);
6747 }
6748 } else {
6749 /* No socket specified, use default */
6750
1/2
✓ Branch 0 taken 46051 times.
✗ Branch 1 not taken.
46051 dynstr_set(&ds_sock, unix_sock);
6751 }
6752
3/8
✓ Branch 0 taken 46252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46252 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 46252 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
46252 DBUG_PRINT("info", ("socket: %s", ds_sock.str));
6753
6754 /* Options */
6755 46252 con_options = ds_options.str;
6756 46252 bool con_socket = false, con_tcp = false;
6757
2/2
✓ Branch 0 taken 4504 times.
✓ Branch 1 taken 46243 times.
50747 while (*con_options) {
6758 /* Step past any spaces in beginning of option */
6759
3/4
✓ Branch 0 taken 4530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 4504 times.
4530 while (*con_options && my_isspace(charset_info, *con_options))
6760 26 con_options++;
6761
6762 /* Find end of this option */
6763 4504 char *end = con_options;
6764
4/4
✓ Branch 0 taken 13782 times.
✓ Branch 1 taken 4472 times.
✓ Branch 2 taken 13750 times.
✓ Branch 3 taken 32 times.
18254 while (*end && !my_isspace(charset_info, *end)) end++;
6765
6766 4504 size_t con_option_len = end - con_options;
6767 4504 char cur_con_option[10] = {};
6768
1/2
✓ Branch 0 taken 4504 times.
✗ Branch 1 not taken.
4504 strmake(cur_con_option, con_options, con_option_len);
6769
6770
2/2
✓ Branch 0 taken 4421 times.
✓ Branch 1 taken 83 times.
4504 if (!std::strcmp(cur_con_option, "SSL"))
6771 4421 con_ssl = true;
6772
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 51 times.
83 else if (!std::strcmp(cur_con_option, "COMPRESS"))
6773 32 con_compress = true;
6774
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 48 times.
51 else if (!std::strcmp(cur_con_option, "PIPE"))
6775 3 con_pipe = true;
6776
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 45 times.
48 else if (!std::strcmp(cur_con_option, "SHM"))
6777 3 con_shm = true;
6778
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 38 times.
45 else if (!std::strcmp(cur_con_option, "CLEARTEXT"))
6779 7 con_cleartext_enable = true;
6780
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 35 times.
38 else if (!std::strcmp(cur_con_option, "SOCKET"))
6781 3 con_socket = true;
6782
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 9 times.
35 else if (!std::strcmp(cur_con_option, "TCP"))
6783 26 con_tcp = true;
6784 else
6785 9 die("Illegal option to connect: %s", cur_con_option);
6786
6787 /* Process next option */
6788 4495 con_options = end;
6789 }
6790
6791
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 46240 times.
46243 if (find_connection_by_name(ds_connection_name.str))
6792 3 die("Connection %s already exists", ds_connection_name.str);
6793
6794
2/2
✓ Branch 0 taken 43262 times.
✓ Branch 1 taken 2978 times.
46240 if (next_con != connections_end)
6795 43262 con_slot = next_con;
6796 else {
6797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2978 times.
2978 if (!(con_slot = find_connection_by_name("-closed_connection-")))
6798 die("Connection limit exhausted, you can have max %d connections",
6799 opt_max_connections);
6800 }
6801
6802
2/4
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46240 times.
46240 if (!mysql_init(&con_slot->mysql)) die("Failed on mysql_init()");
6803
6804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46240 times.
46240 if (opt_init_command)
6805 mysql_options(&con_slot->mysql, MYSQL_INIT_COMMAND, opt_init_command);
6806
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 if (opt_connect_timeout)
6807
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 mysql_options(&con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
6808 (void *)&opt_connect_timeout);
6809
6810
4/4
✓ Branch 0 taken 46239 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 46207 times.
46240 if (opt_compress || con_compress)
6811
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 mysql_options(&con_slot->mysql, MYSQL_OPT_COMPRESS, NullS);
6812
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 mysql_options(&con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, nullptr);
6813
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_NAME, charset_info->csname);
6814
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 if (opt_charsets_dir)
6815
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_DIR, opt_charsets_dir);
6816
6817
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46194 times.
46240 if (ds_compression_algorithm.length)
6818 46 mysql_options(&con_slot->mysql, MYSQL_OPT_COMPRESSION_ALGORITHMS,
6819
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 ds_compression_algorithm.str);
6820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46194 times.
46194 else if (opt_compress_algorithm)
6821 mysql_options(&con_slot->mysql, MYSQL_OPT_COMPRESSION_ALGORITHMS,
6822 opt_compress_algorithm);
6823
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 46231 times.
46240 if (ds_zstd_compression_level.length) {
6824 9 char *end = nullptr;
6825 9 opt_zstd_compress_level = strtol(ds_zstd_compression_level.str, &end, 10);
6826 }
6827
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 mysql_options(&con_slot->mysql, MYSQL_OPT_ZSTD_COMPRESSION_LEVEL,
6828 &opt_zstd_compress_level);
6829
6830 /*
6831 If mysqltest --ssl-mode option is set to DISABLED
6832 and connect(.., SSL) command used, set proper opt_ssl_mode.
6833
6834 So, SSL connection is used either:
6835 a) mysqltest --ssl-mode option is NOT set to DISABLED or
6836 b) connect(.., SSL) command used.
6837 */
6838
4/4
✓ Branch 0 taken 46045 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 4349 times.
✓ Branch 3 taken 41696 times.
46240 if (opt_ssl_mode == SSL_MODE_DISABLED && con_ssl) {
6839 4349 opt_ssl_mode =
6840
2/4
✓ Branch 0 taken 4349 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4349 times.
4349 (opt_ssl_ca || opt_ssl_capath) ? SSL_MODE_VERIFY_CA : SSL_MODE_REQUIRED;
6841 }
6842
2/4
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46240 times.
46240 if (SSL_SET_OPTIONS(&con_slot->mysql)) die("%s", SSL_SET_OPTIONS_ERROR);
6843 46240 opt_ssl_mode = save_opt_ssl_mode;
6844
6845
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 46237 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
46240 if (con_pipe && !con_ssl) {
6846 3 opt_protocol = MYSQL_PROTOCOL_PIPE;
6847 }
6848
6849
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 46237 times.
46240 if (opt_protocol) {
6850
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
6851 /*
6852 Resetting the opt_protocol value to 0 to avoid the
6853 possible failure in the next connect() command.
6854 */
6855 3 opt_protocol = 0;
6856 }
6857
6858
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 46237 times.
46240 if (con_shm) {
6859 3 uint protocol = MYSQL_PROTOCOL_MEMORY;
6860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!ds_shm.length) die("Missing shared memory base name");
6861
6862
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str);
6863
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
6864
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46237 times.
46237 } else if (shared_memory_base_name) {
6865 mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
6866 shared_memory_base_name);
6867 }
6868
6869
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 46237 times.
46240 if (con_socket) {
6870 3 uint protocol = MYSQL_PROTOCOL_SOCKET;
6871
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
6872 }
6873
6874
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 46217 times.
46240 if (con_tcp) {
6875 23 uint protocol = MYSQL_PROTOCOL_TCP;
6876
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
6877 }
6878
6879 /* Use default db name */
6880
3/4
✓ Branch 0 taken 11831 times.
✓ Branch 1 taken 34409 times.
✓ Branch 2 taken 11831 times.
✗ Branch 3 not taken.
46240 if (ds_database.length == 0) dynstr_set(&ds_database, opt_db);
6881
6882
2/4
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46240 times.
✗ Branch 3 not taken.
46240 if (opt_plugin_dir && *opt_plugin_dir)
6883
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 mysql_options(&con_slot->mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
6884
6885
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 46213 times.
46240 if (ds_default_auth.length)
6886
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 mysql_options(&con_slot->mysql, MYSQL_DEFAULT_AUTH, ds_default_auth.str);
6887
6888 /* Set server public_key */
6889
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 set_server_public_key(&con_slot->mysql);
6890
6891
1/2
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
46240 set_get_server_public_key_option(&con_slot->mysql);
6892
6893
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 46233 times.
46240 if (con_cleartext_enable)
6894
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 mysql_options(&con_slot->mysql, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
6895 (char *)&con_cleartext_enable);
6896
6897 46240 unsigned int factor = 0;
6898
2/2
✓ Branch 0 taken 2531 times.
✓ Branch 1 taken 43709 times.
46240 if (ds_password1.length) {
6899 2531 factor = 1;
6900 2531 mysql_options4(&con_slot->mysql, MYSQL_OPT_USER_PASSWORD, &factor,
6901
1/2
✓ Branch 0 taken 2531 times.
✗ Branch 1 not taken.
2531 ds_password1.str);
6902 }
6903 /* set second and third password */
6904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46240 times.
46240 if (ds_password2.length) {
6905 factor = 2;
6906 mysql_options4(&con_slot->mysql, MYSQL_OPT_USER_PASSWORD, &factor,
6907 ds_password2.str);
6908 }
6909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46240 times.
46240 if (ds_password3.length) {
6910 factor = 3;
6911 mysql_options4(&con_slot->mysql, MYSQL_OPT_USER_PASSWORD, &factor,
6912 ds_password3.str);
6913 }
6914
6915 /* Special database to allow one to connect without a database name */
6916
3/4
✓ Branch 0 taken 46240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 46180 times.
46240 if (ds_database.length && !std::strcmp(ds_database.str, "*NO-ONE*"))
6917
1/2
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
60 dynstr_set(&ds_database, "");
6918
6919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46240 times.
46240 if (getenv("EXTERN")) {
6920 dynstr_set(&ds_host, opt_host);
6921 }
6922
6923
2/2
✓ Branch 0 taken 45552 times.
✓ Branch 1 taken 685 times.
46237 if (connect_n_handle_errors(command, &con_slot->mysql, ds_host.str,
6924 46240 ds_user.str, ds_password1.str, ds_database.str,
6925
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46240 con_port, ds_sock.str)) {
6926
3/8
✓ Branch 0 taken 45552 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45552 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 45552 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
45552 DBUG_PRINT("info", ("Inserting connection %s in connection pool",
6927 ds_connection_name.str));
6928
1/2
✓ Branch 0 taken 45552 times.
✗ Branch 1 not taken.
45552 my_free(con_slot->name);
6929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45552 times.
45552 if (!(con_slot->name = my_strdup(PSI_NOT_INSTRUMENTED,
6930
1/2
✓ Branch 0 taken 45552 times.
✗ Branch 1 not taken.
45552 ds_connection_name.str, MYF(MY_WME))))
6931 die("Out of memory");
6932 45552 con_slot->name_len = std::strlen(con_slot->name);
6933
1/2
✓ Branch 0 taken 45552 times.
✗ Branch 1 not taken.
45552 set_current_connection(con_slot);
6934
6935
2/2
✓ Branch 0 taken 42574 times.
✓ Branch 1 taken 2978 times.
45552 if (con_slot == next_con)
6936 42574 next_con++; /* if we used the next_con slot, advance the pointer */
6937 }
6938
6939
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_connection_name);
6940
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_host);
6941
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_user);
6942
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_password1);
6943
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_database);
6944
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_port);
6945
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_sock);
6946
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_options);
6947
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_default_auth);
6948
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_shm);
6949
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_compression_algorithm);
6950
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_zstd_compression_level);
6951
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_password2);
6952
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46237 dynstr_free(&ds_password3);
6953 46237 }
6954
6955 179382994 static int do_done(struct st_command *command) {
6956 /* Check if empty block stack */
6957
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 179382985 times.
179382994 if (cur_block == block_stack) {
6958
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 if (*command->query != '}')
6959 6 die("Stray 'end' command - end of block before beginning");
6960 3 die("Stray '}' - end of block before beginning");
6961 }
6962
6963 /* Test if inner block has been executed */
6964
4/4
✓ Branch 0 taken 6847669 times.
✓ Branch 1 taken 172535316 times.
✓ Branch 2 taken 2578883 times.
✓ Branch 3 taken 4268786 times.
179382985 if (cur_block->ok && cur_block->cmd == cmd_while) {
6965 /* Pop block from stack, re-execute outer block */
6966 2578883 cur_block--;
6967 2578883 parser.current_line = cur_block->line;
6968 } else {
6969
2/2
✓ Branch 0 taken 12651660 times.
✓ Branch 1 taken 164152442 times.
176804102 if (*cur_block->delim) {
6970 /* Restore "old" delimiter after false if block */
6971 12651660 strcpy(delimiter, cur_block->delim);
6972 12651660 delimiter_length = std::strlen(delimiter);
6973 }
6974 /* Pop block from stack, goto next line */
6975 176804102 cur_block--;
6976 176804102 parser.current_line++;
6977 }
6978 179382985 return 0;
6979 }
6980
6981 /* Operands available in if or while conditions */
6982
6983 enum block_op { EQ_OP, NE_OP, GT_OP, GE_OP, LT_OP, LE_OP, ILLEG_OP };
6984
6985 3614291 static enum block_op find_operand(const char *start) {
6986 3614291 char first = *start;
6987 3614291 char next = *(start + 1);
6988
6989
3/4
✓ Branch 0 taken 2246833 times.
✓ Branch 1 taken 1367458 times.
✓ Branch 2 taken 2246833 times.
✗ Branch 3 not taken.
3614291 if (first == '=' && next == '=') return EQ_OP;
6990
3/4
✓ Branch 0 taken 708650 times.
✓ Branch 1 taken 658808 times.
✓ Branch 2 taken 708650 times.
✗ Branch 3 not taken.
1367458 if (first == '!' && next == '=') return NE_OP;
6991
4/4
✓ Branch 0 taken 220212 times.
✓ Branch 1 taken 438596 times.
✓ Branch 2 taken 12554 times.
✓ Branch 3 taken 207658 times.
658808 if (first == '>' && next == '=') return GE_OP;
6992
2/2
✓ Branch 0 taken 207658 times.
✓ Branch 1 taken 438596 times.
646254 if (first == '>') return GT_OP;
6993
4/4
✓ Branch 0 taken 438593 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 106983 times.
✓ Branch 3 taken 331610 times.
438596 if (first == '<' && next == '=') return LE_OP;
6994
2/2
✓ Branch 0 taken 331610 times.
✓ Branch 1 taken 3 times.
331613 if (first == '<') return LT_OP;
6995
6996 3 return ILLEG_OP;
6997 }
6998
6999 /*
7000 Process start of a "if" or "while" statement
7001
7002 SYNOPSIS
7003 do_block()
7004 cmd Type of block
7005 q called command
7006
7007 DESCRIPTION
7008 if ([!]<expr>)
7009 {
7010 <block statements>
7011 }
7012
7013 while ([!]<expr>)
7014 {
7015 <block statements>
7016 }
7017
7018 assert (expr)
7019
7020 Evaluates the <expr> and if it evaluates to
7021 greater than zero executes the following code block.
7022 A '!' can be used before the <expr> to indicate it should
7023 be executed if it evaluates to zero.
7024
7025 In the assert() case, the block is an implied { die [query]; }
7026
7027 <expr> can also be a simple comparison condition:
7028
7029 <variable> <op> <expr>
7030
7031 The left hand side must be a variable, the right hand side can be a
7032 variable, number, string or `query`. Operands are ==, !=, <, <=, >, >=.
7033 == and != can be used for strings, all can be used for numerical values.
7034 */
7035
7036 179396919 static void do_block(enum block_cmd cmd, struct st_command *command) {
7037 179396919 const char *p = command->first_argument;
7038 const char *expr_start;
7039 const char *expr_end;
7040 VAR v;
7041 const char *cmd_name;
7042
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 179396719 times.
179396919 if (cmd == cmd_assert)
7043 200 cmd_name = "assert";
7044 else
7045
2/2
✓ Branch 0 taken 8557137 times.
✓ Branch 1 taken 170839582 times.
179396719 cmd_name = (cmd == cmd_while ? "while" : "if");
7046 179396919 bool not_expr = false;
7047
1/2
✓ Branch 0 taken 179396919 times.
✗ Branch 1 not taken.
179396919 DBUG_TRACE;
7048
3/8
✓ Branch 0 taken 179396919 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 179396919 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 179396919 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
179396919 DBUG_PRINT("enter", ("%s", cmd_name));
7049
7050 /* Check stack overflow */
7051
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 179396916 times.
179396919 if (cur_block == block_stack_end) die("Nesting too deeply");
7052
7053 /* Set way to find outer block again, increase line counter */
7054 179396916 cur_block->line = parser.current_line++;
7055
7056 /* If this block is ignored */
7057
2/2
✓ Branch 0 taken 159883680 times.
✓ Branch 1 taken 19513236 times.
179396916 if (!cur_block->ok) {
7058
4/4
✓ Branch 0 taken 5603423 times.
✓ Branch 1 taken 154280257 times.
✓ Branch 2 taken 5603399 times.
✓ Branch 3 taken 24 times.
159883680 if (cmd == cmd_if || cmd == cmd_while) {
7059 /* Inner block which comes with the command should be ignored */
7060 159883656 cur_block++;
7061 159883656 cur_block->cmd = cmd;
7062 159883656 cur_block->ok = false;
7063 159883656 cur_block->delim[0] = '\0';
7064 }
7065 /* No need to evaluate the condition */
7066 159883680 return;
7067 }
7068
7069 /* Parse and evaluate test expression */
7070 19513236 expr_start = strchr(p, '(');
7071
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 19513230 times.
19513236 if (!expr_start) die("missing '(' in %s", cmd_name);
7072 19513230 ++expr_start;
7073
7074
2/2
✓ Branch 0 taken 14719 times.
✓ Branch 1 taken 19513230 times.
19527949 while (my_isspace(charset_info, *expr_start)) expr_start++;
7075
7076 /* Check for !<expr> */
7077
2/2
✓ Branch 0 taken 5961888 times.
✓ Branch 1 taken 13551342 times.
19513230 if (*expr_start == '!') {
7078 5961888 not_expr = true;
7079 5961888 expr_start++; /* Step past the '!', then any whitespace */
7080
3/4
✓ Branch 0 taken 5961913 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 5961888 times.
5961913 while (*expr_start && my_isspace(charset_info, *expr_start)) expr_start++;
7081 }
7082 /* Find ending ')' */
7083 19513230 expr_end = strrchr(expr_start, ')');
7084
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 19513227 times.
19513230 if (!expr_end) die("missing ')' in %s", cmd_name);
7085 19513227 p = expr_end + 1;
7086
7087
4/4
✓ Branch 0 taken 37988147 times.
✓ Branch 1 taken 728 times.
✓ Branch 2 taken 18475648 times.
✓ Branch 3 taken 19512499 times.
37988875 while (*p && my_isspace(charset_info, *p)) p++;
7088
2/2
✓ Branch 0 taken 19512499 times.
✓ Branch 1 taken 728 times.
19513227 if (*p) {
7089
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19512499 times.
19512499 if (cmd == cmd_assert)
7090 die("End of line junk detected: \"%s\"", p);
7091
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 19512493 times.
19512499 else if (*p != '{')
7092 6 die("Missing '{' after %s. Found \"%s\"", cmd_name, p);
7093 }
7094
7095
1/2
✓ Branch 0 taken 19513221 times.
✗ Branch 1 not taken.
19513221 var_init(&v, nullptr, 0, nullptr, 0);
7096
7097 /* If expression starts with a variable, it may be a compare condition */
7098
7099
2/2
✓ Branch 0 taken 19283072 times.
✓ Branch 1 taken 230149 times.
19513221 if (*expr_start == '$') {
7100 19283072 const char *curr_ptr = expr_end;
7101
1/2
✓ Branch 0 taken 19283072 times.
✗ Branch 1 not taken.
19283072 eval_expr(&v, expr_start, &curr_ptr, true);
7102
2/2
✓ Branch 0 taken 3571247 times.
✓ Branch 1 taken 19283072 times.
22854319 while (my_isspace(charset_info, *++curr_ptr)) {
7103 }
7104 /* If there was nothing past the variable, skip condition part */
7105
2/2
✓ Branch 0 taken 15668781 times.
✓ Branch 1 taken 3614291 times.
19283072 if (curr_ptr == expr_end) goto NO_COMPARE;
7106
7107 3614291 enum block_op operand = find_operand(curr_ptr);
7108
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3614288 times.
3614291 if (operand == ILLEG_OP)
7109 3 die("Found junk '%.*s' after $variable in condition",
7110 3 (int)(expr_end - curr_ptr), curr_ptr);
7111
7112 /* We could silently allow this, but may be confusing */
7113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3614288 times.
3614288 if (not_expr)
7114 die("Negation and comparison should not be combined, please rewrite");
7115
7116 /* Skip the 1 or 2 chars of the operand, then white space */
7117
4/4
✓ Branch 0 taken 3282678 times.
✓ Branch 1 taken 331610 times.
✓ Branch 2 taken 207658 times.
✓ Branch 3 taken 3075020 times.
3614288 if (operand == LT_OP || operand == GT_OP) {
7118 539268 curr_ptr++;
7119 } else {
7120 3075020 curr_ptr += 2;
7121 }
7122
2/2
✓ Branch 0 taken 3570727 times.
✓ Branch 1 taken 3614288 times.
7185015 while (my_isspace(charset_info, *curr_ptr)) curr_ptr++;
7123
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3614282 times.
3614288 if (curr_ptr == expr_end) die("Missing right operand in comparison");
7124
7125 /* Strip off trailing white space */
7126
2/2
✓ Branch 0 taken 4982 times.
✓ Branch 1 taken 3614282 times.
3619264 while (my_isspace(charset_info, expr_end[-1])) expr_end--;
7127 /* strip off ' or " around the string */
7128
4/4
✓ Branch 0 taken 2722350 times.
✓ Branch 1 taken 891932 times.
✓ Branch 2 taken 51582 times.
✓ Branch 3 taken 2670768 times.
3614282 if (*curr_ptr == '\'' || *curr_ptr == '"') {
7129
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 943514 times.
943514 if (expr_end[-1] != *curr_ptr) die("Unterminated string value");
7130 943514 curr_ptr++;
7131 943514 expr_end--;
7132 }
7133 VAR v2;
7134
1/2
✓ Branch 0 taken 3614282 times.
✗ Branch 1 not taken.
3614282 var_init(&v2, nullptr, 0, nullptr, 0);
7135
1/2
✓ Branch 0 taken 3614282 times.
✗ Branch 1 not taken.
3614282 eval_expr(&v2, curr_ptr, &expr_end);
7136
7137
7/8
✓ Branch 0 taken 1367452 times.
✓ Branch 1 taken 2246830 times.
✓ Branch 2 taken 658802 times.
✓ Branch 3 taken 708650 times.
✓ Branch 4 taken 658802 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 658799 times.
3614282 if ((operand != EQ_OP && operand != NE_OP) && !(v.is_int && v2.is_int))
7138 3 die("Only == and != are supported for string values");
7139
7140 /* Now we overwrite the first variable with 0 or 1 (for false or true) */
7141
7142
6/8
✓ Branch 0 taken 2246830 times.
✓ Branch 1 taken 708650 times.
✓ Branch 2 taken 331610 times.
✓ Branch 3 taken 106983 times.
✓ Branch 4 taken 207655 times.
✓ Branch 5 taken 12551 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3614279 switch (operand) {
7143 2246830 case EQ_OP:
7144
2/2
✓ Branch 0 taken 735380 times.
✓ Branch 1 taken 1511450 times.
2246830 if (v.is_int)
7145
4/4
✓ Branch 0 taken 689075 times.
✓ Branch 1 taken 46305 times.
✓ Branch 2 taken 76028 times.
✓ Branch 3 taken 613047 times.
735380 v.int_val = (v2.is_int && v2.int_val == v.int_val);
7146 else
7147 1511450 v.int_val = !std::strcmp(v.str_val, v2.str_val);
7148 2246830 break;
7149
7150 708650 case NE_OP:
7151
2/2
✓ Branch 0 taken 511298 times.
✓ Branch 1 taken 197352 times.
708650 if (v.is_int)
7152
4/4
✓ Branch 0 taken 507131 times.
✓ Branch 1 taken 4167 times.
✓ Branch 2 taken 20614 times.
✓ Branch 3 taken 486517 times.
511298 v.int_val = !(v2.is_int && v2.int_val == v.int_val);
7153 else
7154 197352 v.int_val = (std::strcmp(v.str_val, v2.str_val) != 0);
7155 708650 break;
7156
7157 331610 case LT_OP:
7158 331610 v.int_val = (v.int_val < v2.int_val);
7159 331610 break;
7160 106983 case LE_OP:
7161 106983 v.int_val = (v.int_val <= v2.int_val);
7162 106983 break;
7163 207655 case GT_OP:
7164 207655 v.int_val = (v.int_val > v2.int_val);
7165 207655 break;
7166 12551 case GE_OP:
7167 12551 v.int_val = (v.int_val >= v2.int_val);
7168 12551 break;
7169 case ILLEG_OP:
7170 die("Impossible operator, this cannot happen");
7171 }
7172
7173 3614279 v.is_int = true;
7174
1/2
✓ Branch 0 taken 3614279 times.
✗ Branch 1 not taken.
3614279 my_free(v2.str_val);
7175 } else {
7176
4/4
✓ Branch 0 taken 1556 times.
✓ Branch 1 taken 228593 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1550 times.
230149 if (*expr_start != '`' && !my_isdigit(charset_info, *expr_start))
7177 6 die("Expression in %s() must begin with $, ` or a number", cmd_name);
7178
1/2
✓ Branch 0 taken 230143 times.
✗ Branch 1 not taken.
230143 eval_expr(&v, expr_start, &expr_end);
7179 }
7180
7181 19513203 NO_COMPARE:
7182 /* Evaluate the expression */
7183 bool v_val_bool;
7184
2/2
✓ Branch 0 taken 14170184 times.
✓ Branch 1 taken 5343019 times.
19513203 if (v.is_int) {
7185 14170184 v_val_bool = (v.int_val != 0);
7186 } else
7187 /* Any non-empty string which does not begin with 0 is also true */
7188 {
7189 5343019 p = v.str_val;
7190 /* First skip any leading white space or unary -+ */
7191
8/8
✓ Branch 0 taken 930074 times.
✓ Branch 1 taken 4413656 times.
✓ Branch 2 taken 169 times.
✓ Branch 3 taken 929905 times.
✓ Branch 4 taken 540 times.
✓ Branch 5 taken 929365 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 929363 times.
5343730 while (*p && ((my_isspace(charset_info, *p) || *p == '-' || *p == '+')))
7192 711 p++;
7193
4/4
✓ Branch 0 taken 929363 times.
✓ Branch 1 taken 4413656 times.
✓ Branch 2 taken 916617 times.
✓ Branch 3 taken 12746 times.
5343019 v_val_bool = (*p && *p != '0');
7194 }
7195
2/2
✓ Branch 0 taken 5961888 times.
✓ Branch 1 taken 13551315 times.
19513203 if (not_expr) v_val_bool = !v_val_bool;
7196
7197 /* Finally, handle assert/if/while */
7198
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 19513030 times.
19513203 if (cmd == cmd_assert) {
7199
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 152 times.
173 if (!v_val_bool) {
7200 21 die("Assertion failed: %s", command->query);
7201 }
7202 } else {
7203 /* Define inner block */
7204 19513030 cur_block++;
7205 19513030 cur_block->cmd = cmd;
7206 19513030 cur_block->ok = v_val_bool;
7207
7208
2/2
✓ Branch 0 taken 6861364 times.
✓ Branch 1 taken 12651666 times.
19513030 if (v_val_bool) {
7209 6861364 cur_block->delim[0] = '\0';
7210 } else {
7211 /* Remember "old" delimiter if entering a false if block */
7212 12651666 strcpy(cur_block->delim, delimiter);
7213 }
7214 }
7215
7216
3/8
✓ Branch 0 taken 19513182 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19513182 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19513182 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
19513182 DBUG_PRINT("info", ("OK: %d", v_val_bool));
7217
1/2
✓ Branch 0 taken 19513182 times.
✗ Branch 1 not taken.
19513182 my_free(v.str_val);
7218
2/2
✓ Branch 0 taken 19513182 times.
✓ Branch 1 taken 159883680 times.
179396862 }
7219
7220 109446 static void do_delimiter(struct st_command *command) {
7221 109446 char *p = command->first_argument;
7222
1/2
✓ Branch 0 taken 109446 times.
✗ Branch 1 not taken.
109446 DBUG_TRACE;
7223
3/8
✓ Branch 0 taken 109446 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 109446 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 109446 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
109446 DBUG_PRINT("enter", ("first_argument: %s", command->first_argument));
7224
7225
2/4
✓ Branch 0 taken 109446 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 109446 times.
109446 while (*p && my_isspace(charset_info, *p)) p++;
7226
7227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109446 times.
109446 if (!(*p)) die("Can't set empty delimiter");
7228
7229
1/2
✓ Branch 0 taken 109446 times.
✗ Branch 1 not taken.
109446 strmake(delimiter, p, sizeof(delimiter) - 1);
7230 109446 delimiter_length = std::strlen(delimiter);
7231
7232
3/8
✓ Branch 0 taken 109446 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 109446 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 109446 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
109446 DBUG_PRINT("exit", ("delimiter: %s", delimiter));
7233 109446 command->last_argument = p + delimiter_length;
7234 109446 }
7235
7236 /*
7237 do_reset_connection
7238
7239 DESCRIPTION
7240 Reset the current session.
7241 */
7242 31 static void do_reset_connection() {
7243 31 MYSQL *mysql = &cur_con->mysql;
7244
7245
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 DBUG_TRACE;
7246
3/4
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 30 times.
31 if (mysql_reset_connection(mysql))
7247
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 die("reset connection failed: %s", mysql_error(mysql));
7248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (cur_con->stmt) {
7249 mysql_stmt_close(cur_con->stmt);
7250 cur_con->stmt = nullptr;
7251 }
7252 30 }
7253
7254 2036768945 bool match_delimiter(int c, const char *delim, size_t length) {
7255 uint i;
7256 char tmp[MAX_DELIMITER_LENGTH];
7257
7258
2/2
✓ Branch 0 taken 2019585532 times.
✓ Branch 1 taken 17183413 times.
2036768945 if (c != *delim) return false;
7259
7260
7/8
✓ Branch 0 taken 5209634 times.
✓ Branch 1 taken 12980650 times.
✓ Branch 2 taken 5209634 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1006871 times.
✓ Branch 5 taken 4202763 times.
✓ Branch 6 taken 1006871 times.
✓ Branch 7 taken 17183413 times.
18190284 for (i = 1; i < length && (c = my_getc(cur_file->file)) == *(delim + i); i++)
7261 1006871 tmp[i] = c;
7262
7263
2/2
✓ Branch 0 taken 12980650 times.
✓ Branch 1 taken 4202763 times.
17183413 if (i == length) return true; /* Found delimiter */
7264
7265 /* didn't find delimiter, push back things that we read */
7266 4202763 my_ungetc(c);
7267
2/2
✓ Branch 0 taken 27184 times.
✓ Branch 1 taken 4202763 times.
4229947 while (i > 1) my_ungetc(tmp[--i]);
7268 4202763 return false;
7269 }
7270
7271 1834118066 static bool end_of_query(int c) {
7272 1834118066 return match_delimiter(c, delimiter, delimiter_length);
7273 }
7274
7275 /*
7276 Read one "line" from the file
7277
7278 SYNOPSIS
7279 read_line
7280 buf buffer for the read line
7281 size size of the buffer i.e max size to read
7282
7283 DESCRIPTION
7284 This function actually reads several lines and adds them to the
7285 buffer buf. It continues to read until it finds what it believes
7286 is a complete query.
7287
7288 Normally that means it will read lines until it reaches the
7289 "delimiter" that marks end of query. Default delimiter is ';'
7290 The function should be smart enough not to detect delimiter's
7291 found inside strings surrounded with '"' and '\'' escaped strings.
7292
7293 If the first line in a query starts with '#' or '-' this line is treated
7294 as a comment. A comment is always terminated when end of line '\n' is
7295 reached.
7296
7297 */
7298
7299 409576039 static int read_line(char *buf, int size) {
7300 409576039 char c, last_quote = 0, last_char = 0;
7301 409576039 char *p = buf, *buf_end = buf + size - 1;
7302 409576039 int skip_char = 0;
7303 409576039 int query_comment = 0, query_comment_start = 0, query_comment_end = 0;
7304 409576039 bool have_slash = false;
7305
7306 enum {
7307 R_NORMAL,
7308 R_Q,
7309 R_SLASH_IN_Q,
7310 R_COMMENT,
7311 R_LINE_START
7312 409576039 } state = R_LINE_START;
7313
1/2
✓ Branch 0 taken 409576039 times.
✗ Branch 1 not taken.
409576039 DBUG_TRACE;
7314
7315 409576039 start_lineno = cur_file->lineno;
7316
3/8
✓ Branch 0 taken 409576039 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 409576039 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 409576039 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
409576039 DBUG_PRINT("info", ("Starting to read at lineno: %d", start_lineno));
7317
1/2
✓ Branch 0 taken 14991182751 times.
✗ Branch 1 not taken.
14991182751 for (; p < buf_end;) {
7318 14991182751 skip_char = 0;
7319
1/2
✓ Branch 0 taken 14991182751 times.
✗ Branch 1 not taken.
14991182751 c = my_getc(cur_file->file);
7320
2/2
✓ Branch 0 taken 4154200 times.
✓ Branch 1 taken 14987028551 times.
14991182751 if (feof(cur_file->file)) {
7321 4154200 found_eof:
7322
2/2
✓ Branch 0 taken 4154162 times.
✓ Branch 1 taken 38 times.
4154200 if (cur_file->file != stdin) {
7323
1/2
✓ Branch 0 taken 4154162 times.
✗ Branch 1 not taken.
4154162 fclose(cur_file->file);
7324 4154162 cur_file->file = nullptr;
7325 }
7326
1/2
✓ Branch 0 taken 4154200 times.
✗ Branch 1 not taken.
4154200 my_free(cur_file->file_name);
7327 4154200 cur_file->file_name = nullptr;
7328
2/2
✓ Branch 0 taken 35816 times.
✓ Branch 1 taken 4118384 times.
4154200 if (cur_file == file_stack) {
7329 /* We're back at the first file, check if
7330 all { have matching }
7331 */
7332
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 35810 times.
35816 if (cur_block != block_stack) die("Missing end of block");
7333
7334 35810 *p = 0;
7335
3/8
✓ Branch 0 taken 35810 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35810 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 35810 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
35810 DBUG_PRINT("info", ("end of file at line %d", cur_file->lineno));
7336 35810 return 1;
7337 }
7338 4118384 cur_file--;
7339 4118384 start_lineno = cur_file->lineno;
7340 4118384 continue;
7341 }
7342
7343
2/2
✓ Branch 0 taken 455235056 times.
✓ Branch 1 taken 14531793495 times.
14987028551 if (c == '\n') {
7344 /* Line counting is independent of state */
7345 455235056 cur_file->lineno++;
7346
7347 /* Convert cr/lf to lf */
7348
4/4
✓ Branch 0 taken 320061638 times.
✓ Branch 1 taken 135173418 times.
✓ Branch 2 taken 975 times.
✓ Branch 3 taken 320060663 times.
455235056 if (p != buf && *(p - 1) == '\r') p--;
7349 }
7350
7351
5/6
✓ Branch 0 taken 1742153946 times.
✓ Branch 1 taken 12189219661 times.
✓ Branch 2 taken 929715324 times.
✓ Branch 3 taken 125908872 times.
✓ Branch 4 taken 30748 times.
✗ Branch 5 not taken.
14987028551 switch (state) {
7352 1742153946 case R_NORMAL:
7353
3/4
✓ Branch 0 taken 1742153946 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12517318 times.
✓ Branch 3 taken 1729636628 times.
1742153946 if (end_of_query(c)) {
7354 12517318 *p = 0;
7355
3/8
✓ Branch 0 taken 12517318 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12517318 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12517318 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
12517318 DBUG_PRINT("exit", ("Found delimiter '%s' at line %d", delimiter,
7356 cur_file->lineno));
7357 12517318 return 0;
7358
2/2
✓ Branch 0 taken 39897045 times.
✓ Branch 1 taken 1689739583 times.
1769533673 } else if ((c == '{' &&
7359
2/2
✓ Branch 0 taken 38593645 times.
✓ Branch 1 taken 1303400 times.
39897045 (!charset_info->coll->strnncoll(
7360 charset_info, (const uchar *)"while", 5, (uchar *)buf,
7361
1/2
✓ Branch 0 taken 39897045 times.
✗ Branch 1 not taken.
39897045 std::min<ptrdiff_t>(5, p - buf), false) ||
7362
2/2
✓ Branch 0 taken 38426526 times.
✓ Branch 1 taken 167119 times.
38593645 !charset_info->coll->strnncoll(
7363 charset_info, (const uchar *)"if", 2, (uchar *)buf,
7364
3/4
✓ Branch 0 taken 38593645 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39729926 times.
✓ Branch 3 taken 1689906702 times.
1768230273 std::min<ptrdiff_t>(2, p - buf), false)))) {
7365 /* Only if and while commands can be terminated by { */
7366 39729926 *p++ = c;
7367 39729926 *p = 0;
7368
3/8
✓ Branch 0 taken 39729926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39729926 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 39729926 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
39729926 DBUG_PRINT("exit", ("Found '{' indicating start of block at line %d",
7369 cur_file->lineno));
7370 39729926 return 0;
7371
6/6
✓ Branch 0 taken 1684325359 times.
✓ Branch 1 taken 5581343 times.
✓ Branch 2 taken 1683404979 times.
✓ Branch 3 taken 920380 times.
✓ Branch 4 taken 828671 times.
✓ Branch 5 taken 1682576308 times.
1689906702 } else if (c == '\'' || c == '"' || c == '`') {
7372
2/2
✓ Branch 0 taken 7330294 times.
✓ Branch 1 taken 100 times.
7330394 if (!have_slash) {
7373 7330294 last_quote = c;
7374 7330294 state = R_Q;
7375 }
7376
2/2
✓ Branch 0 taken 207518 times.
✓ Branch 1 taken 1682368790 times.
1682576308 } else if (c == '/') {
7377
4/4
✓ Branch 0 taken 204220 times.
✓ Branch 1 taken 3298 times.
✓ Branch 2 taken 201888 times.
✓ Branch 3 taken 2332 times.
207518 if ((query_comment_start == 0) && (query_comment == 0))
7378 201888 query_comment_start = 1;
7379
2/2
✓ Branch 0 taken 2325 times.
✓ Branch 1 taken 3305 times.
5630 else if (query_comment_end == 1) {
7380 2325 query_comment = 0;
7381 2325 query_comment_end = 0;
7382 }
7383
2/2
✓ Branch 0 taken 4727463 times.
✓ Branch 1 taken 1677641327 times.
1682368790 } else if (c == '*') {
7384
4/4
✓ Branch 0 taken 2343 times.
✓ Branch 1 taken 4725120 times.
✓ Branch 2 taken 2340 times.
✓ Branch 3 taken 3 times.
4727463 if ((query_comment == 1) && (query_comment_end == 0))
7385 2340 query_comment_end = 1;
7386
2/2
✓ Branch 0 taken 4423 times.
✓ Branch 1 taken 4720700 times.
4725123 else if (query_comment_start == 1)
7387 4423 query_comment = 1;
7388
4/4
✓ Branch 0 taken 1677375227 times.
✓ Branch 1 taken 266100 times.
✓ Branch 2 taken 13835119 times.
✓ Branch 3 taken 1663540108 times.
1677641327 } else if ((c == '+') || (c == '!')) {
7389
4/4
✓ Branch 0 taken 2090 times.
✓ Branch 1 taken 14099129 times.
✓ Branch 2 taken 2087 times.
✓ Branch 3 taken 3 times.
14101219 if ((query_comment_start == 1) && (query_comment == 1)) {
7390 2087 query_comment_start = 0;
7391 2087 query_comment = 0;
7392 }
7393
2/2
✓ Branch 0 taken 196046 times.
✓ Branch 1 taken 1663344062 times.
1663540108 } else if (query_comment_start == 1)
7394 196046 query_comment_start = 0;
7395
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1663344047 times.
1663344062 else if (query_comment_end == 1)
7396 15 query_comment_end = 0;
7397
7398 1689906702 have_slash = (c == '\\');
7399 1689906702 break;
7400
7401 12189219661 case R_COMMENT:
7402
2/2
✓ Branch 0 taken 289764297 times.
✓ Branch 1 taken 11899455364 times.
12189219661 if (c == '\n') {
7403 /* Comments are terminated by newline */
7404 289764297 *p = 0;
7405
3/8
✓ Branch 0 taken 289764297 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 289764297 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 289764297 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
289764297 DBUG_PRINT("exit", ("Found newline in comment at line: %d",
7406 cur_file->lineno));
7407 289764297 return 0;
7408 }
7409 11899455364 break;
7410
7411 929715324 case R_LINE_START:
7412
4/4
✓ Branch 0 taken 740915417 times.
✓ Branch 1 taken 188799907 times.
✓ Branch 2 taken 100964391 times.
✓ Branch 3 taken 639951026 times.
929715324 if (c == '#' || c == '-') {
7413 /* A # or - in the first position of the line - this is a comment */
7414 289764298 state = R_COMMENT;
7415
2/2
✓ Branch 0 taken 547986906 times.
✓ Branch 1 taken 91964120 times.
639951026 } else if (my_isspace(charset_info, c)) {
7416
2/2
✓ Branch 0 taken 135173418 times.
✓ Branch 1 taken 412813488 times.
547986906 if (c == '\n') {
7417
2/2
✓ Branch 0 taken 27811815 times.
✓ Branch 1 taken 107361603 times.
135173418 if (last_char == '\n') {
7418 /* Two new lines in a row, return empty line */
7419
3/8
✓ Branch 0 taken 27811815 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27811815 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 27811815 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
27811815 DBUG_PRINT("info", ("Found two new lines in a row"));
7420 27811815 *p++ = c;
7421 27811815 *p = 0;
7422 27811815 return 0;
7423 }
7424
7425 /* Query hasn't started yet */
7426 107361603 start_lineno = cur_file->lineno;
7427
3/8
✓ Branch 0 taken 107361603 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 107361603 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 107361603 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
107361603 DBUG_PRINT("info", ("Query hasn't started yet, start_lineno: %d",
7428 start_lineno));
7429 }
7430
7431 /* Skip all space at beginning of line */
7432 520175091 skip_char = 1;
7433
3/4
✓ Branch 0 taken 91964120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 91964119 times.
91964120 } else if (end_of_query(c)) {
7434 1 *p = 0;
7435
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 DBUG_PRINT("exit", ("Found delimiter '%s' at line: %d", delimiter,
7436 cur_file->lineno));
7437 1 return 0;
7438
2/2
✓ Branch 0 taken 39716866 times.
✓ Branch 1 taken 52247253 times.
91964119 } else if (c == '}') {
7439 /* A "}" need to be by itself in the beginning of a line to terminate
7440 */
7441 39716866 *p++ = c;
7442 39716866 *p = 0;
7443
3/8
✓ Branch 0 taken 39716866 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39716866 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 39716866 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
39716866 DBUG_PRINT("exit", ("Found '}' in begining of a line at line: %d",
7444 cur_file->lineno));
7445 39716866 return 0;
7446
3/6
✓ Branch 0 taken 52247253 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52247253 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 52247253 times.
52247253 } else if (c == '\'' || c == '"' || c == '`') {
7447 last_quote = c;
7448 state = R_Q;
7449 } else
7450 52247253 state = R_NORMAL;
7451 862186642 break;
7452
7453 125908872 case R_Q:
7454
2/2
✓ Branch 0 taken 7330043 times.
✓ Branch 1 taken 118578829 times.
125908872 if (c == last_quote)
7455 7330043 state = R_NORMAL;
7456
2/2
✓ Branch 0 taken 30748 times.
✓ Branch 1 taken 118548081 times.
118578829 else if (c == '\\')
7457 30748 state = R_SLASH_IN_Q;
7458
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 118547830 times.
118548081 else if (query_comment)
7459 251 state = R_NORMAL;
7460 125908872 break;
7461
7462 30748 case R_SLASH_IN_Q:
7463 30748 state = R_Q;
7464 30748 break;
7465 }
7466
7467 14577488328 last_char = c;
7468
7469
2/2
✓ Branch 0 taken 14057313237 times.
✓ Branch 1 taken 520175091 times.
14577488328 if (!skip_char) {
7470 /* Could be a multibyte character */
7471 /* This code is based on the code in "sql_load.cc" */
7472 uint charlen;
7473
2/2
✓ Branch 0 taken 14057294013 times.
✓ Branch 1 taken 19224 times.
14057313237 if (my_mbmaxlenlen(charset_info) == 1)
7474
1/2
✓ Branch 0 taken 14057294013 times.
✗ Branch 1 not taken.
14057294013 charlen = my_mbcharlen(charset_info, (unsigned char)c);
7475 else {
7476
3/4
✓ Branch 0 taken 19224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1856 times.
✓ Branch 3 taken 17368 times.
19224 if (!(charlen = my_mbcharlen(charset_info, (unsigned char)c))) {
7477
1/2
✓ Branch 0 taken 1856 times.
✗ Branch 1 not taken.
1856 int c1 = my_getc(cur_file->file);
7478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1856 times.
1856 if (c1 == EOF) {
7479 *p++ = c;
7480 goto found_eof;
7481 }
7482
7483 charlen =
7484
1/2
✓ Branch 0 taken 1856 times.
✗ Branch 1 not taken.
1856 my_mbcharlen_2(charset_info, (unsigned char)c, (unsigned char)c1);
7485 1856 my_ungetc(c1);
7486 }
7487 }
7488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14057313237 times.
14057313237 if (charlen == 0) return 1;
7489 /* We give up if multibyte character is started but not */
7490 /* completed before we pass buf_end */
7491
3/4
✓ Branch 0 taken 160194 times.
✓ Branch 1 taken 14057153043 times.
✓ Branch 2 taken 160194 times.
✗ Branch 3 not taken.
14057313237 if ((charlen > 1) && (p + charlen) <= buf_end) {
7492 160194 char *mb_start = p;
7493
7494 160194 *p++ = c;
7495
7496
2/2
✓ Branch 0 taken 209386 times.
✓ Branch 1 taken 160194 times.
369580 for (uint i = 1; i < charlen; i++) {
7497
1/2
✓ Branch 0 taken 209386 times.
✗ Branch 1 not taken.
209386 c = my_getc(cur_file->file);
7498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209386 times.
209386 if (feof(cur_file->file)) goto found_eof;
7499 209386 *p++ = c;
7500 }
7501
3/4
✓ Branch 0 taken 160194 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 254 times.
✓ Branch 3 taken 159940 times.
160194 if (!my_ismbchar(charset_info, mb_start, p)) {
7502 /* It was not a multiline char, push back the characters */
7503 /* We leave first 'c', i.e. pretend it was a normal char */
7504
2/2
✓ Branch 0 taken 303 times.
✓ Branch 1 taken 254 times.
557 while (p - 1 > mb_start) my_ungetc(*--p);
7505 }
7506 160194 } else
7507 14057153043 *p++ = c;
7508 }
7509 }
7510 die("The input buffer is too small for this query.x\n"
7511 "check your query or increase MAX_QUERY and recompile");
7512 return 0;
7513 409576033 }
7514
7515 /// Set string query attributes for the next query
7516 ///
7517 /// @param command Pointer to the st_command structure which holds the
7518 /// arguments and information for the command. Optionally
7519 /// including a timeout else the default of 60 seconds
7520 10 static void do_query_attributes(struct st_command *command) {
7521 10 const char *from = command->first_argument;
7522 char *buff, *start;
7523
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 DBUG_TRACE;
7524
7525
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 global_attrs->clear();
7526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!*from) die("Missing argument in %s", command->query);
7527
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 start = buff = (char *)my_malloc(PSI_NOT_INSTRUMENTED, std::strlen(from) + 1,
7528 MYF(MY_WME | MY_FAE));
7529
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 10 times.
21 while (*from) {
7530
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 char *name = get_string(&buff, &from, command);
7531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (!*from)
7532 die("Wrong (odd) number of arguments to query_attributes in '%s'",
7533 command->query);
7534
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 char *value = get_string(&buff, &from, command);
7535
7536
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (global_attrs->push_param(name, value))
7537 die("Failed to add an attribute pair in query_attributes");
7538 }
7539
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 my_free(start);
7540 10 command->last_argument = command->end;
7541 10 }
7542
7543 /*
7544 Convert the read query to result format version 1
7545
7546 That is: After newline, all spaces need to be skipped
7547 unless the previous char was a quote
7548
7549 This is due to an old bug that has now been fixed, but the
7550 version 1 output format is preserved by using this function
7551
7552 */
7553
7554 409540223 static void convert_to_format_v1(char *query) {
7555 409540223 int last_c_was_quote = 0;
7556 409540223 char *p = query, *to = query;
7557 409540223 char *end = strend(query);
7558 char last_c;
7559
7560
2/2
✓ Branch 0 taken 12651294426 times.
✓ Branch 1 taken 409540223 times.
13060834649 while (p <= end) {
7561
4/4
✓ Branch 0 taken 58035104 times.
✓ Branch 1 taken 12593259322 times.
✓ Branch 2 taken 57808474 times.
✓ Branch 3 taken 226630 times.
12651294426 if (*p == '\n' && !last_c_was_quote) {
7562 57808474 *to++ = *p++; /* Save the newline */
7563
7564 /* Skip any spaces on next line */
7565
4/4
✓ Branch 0 taken 78522817 times.
✓ Branch 1 taken 27845538 times.
✓ Branch 2 taken 48559881 times.
✓ Branch 3 taken 29962936 times.
106368355 while (*p && my_isspace(charset_info, *p)) p++;
7566
7567 57808474 last_c_was_quote = 0;
7568
6/6
✓ Branch 0 taken 12564924647 times.
✓ Branch 1 taken 28561305 times.
✓ Branch 2 taken 12563182252 times.
✓ Branch 3 taken 1742395 times.
✓ Branch 4 taken 17691355 times.
✓ Branch 5 taken 12545490897 times.
12593485952 } else if (*p == '\'' || *p == '"' || *p == '`') {
7569 47995055 last_c = *p;
7570 47995055 *to++ = *p++;
7571
7572 /* Copy anything until the next quote of same type */
7573
4/4
✓ Branch 0 taken 1869158773 times.
✓ Branch 1 taken 5306542 times.
✓ Branch 2 taken 1826470260 times.
✓ Branch 3 taken 42688513 times.
1874465315 while (*p && *p != last_c) *to++ = *p++;
7574
7575 47995055 *to++ = *p++;
7576
7577 47995055 last_c_was_quote = 1;
7578 } else {
7579 12545490897 *to++ = *p++;
7580 12545490897 last_c_was_quote = 0;
7581 }
7582 }
7583 409540223 }
7584
7585 /*
7586 Check for unexpected "junk" after the end of query
7587 This is normally caused by missing delimiters or when
7588 switching between different delimiters
7589 */
7590
7591 164653297 void check_eol_junk_line(const char *line) {
7592 164653297 const char *p = line;
7593
1/2
✓ Branch 0 taken 164653297 times.
✗ Branch 1 not taken.
164653297 DBUG_TRACE;
7594
3/8
✓ Branch 0 taken 164653297 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164653297 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 164653297 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
164653297 DBUG_PRINT("enter", ("line: %s", line));
7595
7596 /* Check for extra delimiter */
7597
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 164653273 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 18 times.
164653297 if (*p && !std::strncmp(p, delimiter, delimiter_length))
7598 6 die("Extra delimiter \"%s\" found", delimiter);
7599
7600 /* Allow trailing # comment */
7601
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 164653273 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
164653291 if (*p && *p != '#') {
7602
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (*p == '\n') die("Missing delimiter");
7603 18 die("End of line junk detected: \"%s\"", p);
7604 }
7605 164653273 }
7606
7607 164128409 static void check_eol_junk(const char *eol) {
7608 164128409 const char *p = eol;
7609
1/2
✓ Branch 0 taken 164128409 times.
✗ Branch 1 not taken.
164128409 DBUG_TRACE;
7610
3/8
✓ Branch 0 taken 164128409 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164128409 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 164128409 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
164128409 DBUG_PRINT("enter", ("eol: %s", eol));
7611
7612 /* Skip past all spacing chars and comments */
7613
7/8
✓ Branch 0 taken 7528 times.
✓ Branch 1 taken 164128388 times.
✓ Branch 2 taken 4247 times.
✓ Branch 3 taken 3281 times.
✓ Branch 4 taken 3260 times.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 21 times.
164135916 while (*p && (my_isspace(charset_info, *p) || *p == '#' || *p == '\n')) {
7614 /* Skip past comments started with # and ended with newline */
7615
3/4
✓ Branch 0 taken 7507 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3260 times.
✓ Branch 3 taken 4247 times.
7507 if (*p && *p == '#') {
7616 3260 p++;
7617
3/4
✓ Branch 0 taken 103670 times.
✓ Branch 1 taken 3260 times.
✓ Branch 2 taken 103670 times.
✗ Branch 3 not taken.
106930 while (*p && *p != '\n') p++;
7618 }
7619
7620 /* Check this line */
7621
3/6
✓ Branch 0 taken 4247 times.
✓ Branch 1 taken 3260 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4247 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7507 if (*p && *p == '\n') check_eol_junk_line(p);
7622
7623
2/2
✓ Branch 0 taken 4247 times.
✓ Branch 1 taken 3260 times.
7507 if (*p) p++;
7624 }
7625
7626
1/2
✓ Branch 0 taken 164128388 times.
✗ Branch 1 not taken.
164128409 check_eol_junk_line(p);
7627 164128388 }
7628
7629 935926106 static bool is_delimiter(const char *p) {
7630 935926106 uint match = 0;
7631 935926106 char *delim = delimiter;
7632
6/6
✓ Branch 0 taken 935926124 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 935926041 times.
✓ Branch 4 taken 83 times.
✓ Branch 5 taken 935926106 times.
935926189 while (*p && *p == *delim++) {
7633 83 match++;
7634 83 p++;
7635 }
7636
7637 935926106 return (match == delimiter_length);
7638 }
7639
7640 // 256K -- a test in sp-big is >128K
7641 #define MAX_QUERY (256 * 1024 * 2)
7642 static char read_command_buf[MAX_QUERY];
7643
7644 /// Create a command from a set of lines.
7645 ///
7646 /// Converts lines returned by read_line into a command, this involves
7647 /// parsing the first word in the read line to find the command type.
7648 ///
7649 /// A '`--`' comment may contain a valid query as the first word after
7650 /// the comment start. Thus it's always checked to see if that is the
7651 /// case. The advantage with this approach is to be able to execute
7652 /// commands terminated by new line '\n' regardless how many "delimiter"
7653 /// it contain.
7654 ///
7655 /// @param [in] command_ptr pointer where to return the new query
7656 ///
7657 /// @retval 0 on success, else 1
7658 1824062904 static int read_command(struct st_command **command_ptr) {
7659 1824062904 char *p = read_command_buf;
7660
1/2
✓ Branch 0 taken 1824062904 times.
✗ Branch 1 not taken.
1824062904 DBUG_TRACE;
7661
7662
2/2
✓ Branch 0 taken 1414486865 times.
✓ Branch 1 taken 409576039 times.
1824062904 if (parser.current_line < parser.read_lines) {
7663
1/2
✓ Branch 0 taken 1414486865 times.
✗ Branch 1 not taken.
1414486865 *command_ptr = q_lines->at(parser.current_line);
7664 // Assign the current command line number
7665 1414486865 start_lineno = (*command_ptr)->lineno;
7666 1414486865 return 0;
7667 }
7668
7669 struct st_command *command;
7670
1/2
✓ Branch 0 taken 409576039 times.
✗ Branch 1 not taken.
409576039 if (!(*command_ptr = command = (struct st_command *)my_malloc(
7671 PSI_NOT_INSTRUMENTED, sizeof(*command),
7672
2/4
✓ Branch 0 taken 409576039 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 409576039 times.
819152078 MYF(MY_WME | MY_ZEROFILL))) ||
7673
2/4
✓ Branch 0 taken 409576039 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 409576039 times.
409576039 q_lines->push_back(command))
7674 die("Out of memory");
7675 409576039 command->type = Q_UNKNOWN;
7676
7677 409576039 read_command_buf[0] = 0;
7678
3/4
✓ Branch 0 taken 409576033 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35810 times.
✓ Branch 3 taken 409540223 times.
409576039 if (read_line(read_command_buf, sizeof(read_command_buf))) {
7679
1/2
✓ Branch 0 taken 35801 times.
✗ Branch 1 not taken.
35810 check_eol_junk(read_command_buf);
7680 35801 return 1;
7681 }
7682
7683 // Set the line number for the command
7684 409540223 command->lineno = start_lineno;
7685
7686
1/2
✓ Branch 0 taken 409540223 times.
✗ Branch 1 not taken.
409540223 if (opt_result_format_version == 1) convert_to_format_v1(read_command_buf);
7687
7688
3/8
✓ Branch 0 taken 409540223 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 409540223 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 409540223 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
409540223 DBUG_PRINT("info", ("query: '%s'", read_command_buf));
7689
2/2
✓ Branch 0 taken 188799906 times.
✓ Branch 1 taken 220740317 times.
409540223 if (*p == '#') {
7690 188799906 command->type = Q_COMMENT;
7691
3/4
✓ Branch 0 taken 100964391 times.
✓ Branch 1 taken 119775926 times.
✓ Branch 2 taken 100964391 times.
✗ Branch 3 not taken.
220740317 } else if (p[0] == '-' && p[1] == '-') {
7692 100964391 command->type = Q_COMMENT_WITH_COMMAND;
7693 // Skip past '--'
7694 100964391 p += 2;
7695
2/2
✓ Branch 0 taken 27811815 times.
✓ Branch 1 taken 91964111 times.
119775926 } else if (*p == '\n') {
7696 27811815 command->type = Q_EMPTY_LINE;
7697 }
7698
7699 // Skip leading spaces
7700
4/4
✓ Branch 0 taken 409563207 times.
✓ Branch 1 taken 27811816 times.
✓ Branch 2 taken 27834800 times.
✓ Branch 3 taken 381728407 times.
437375023 while (*p && my_isspace(charset_info, *p)) p++;
7701
7702 819080446 if (!(command->query_buf = command->query =
7703
2/4
✓ Branch 0 taken 409540223 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 409540223 times.
409540223 my_strdup(PSI_NOT_INSTRUMENTED, p, MYF(MY_WME))))
7704 die("Out of memory");
7705
7706 // Calculate first word length(the command), terminated
7707 // by 'space' , '(' or 'delimiter'
7708 409540223 p = command->query;
7709
10/10
✓ Branch 0 taken 1219503963 times.
✓ Branch 1 taken 125962301 times.
✓ Branch 2 taken 936211756 times.
✓ Branch 3 taken 283292207 times.
✓ Branch 4 taken 935926106 times.
✓ Branch 5 taken 285650 times.
✓ Branch 6 taken 935926041 times.
✓ Branch 7 taken 65 times.
✓ Branch 8 taken 935926041 times.
✓ Branch 9 taken 409540223 times.
1345466264 while (*p && !my_isspace(charset_info, *p) && *p != '(' && !is_delimiter(p))
7710 935926041 p++;
7711 409540223 command->first_word_len = (uint)(p - command->query);
7712
3/8
✓ Branch 0 taken 409540223 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 409540223 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 409540223 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
409540223 DBUG_PRINT("info",
7713 ("first_word: %.*s", static_cast<int>(command->first_word_len),
7714 command->query));
7715
7716 // Skip spaces between command and first argument
7717
4/4
✓ Branch 0 taken 805286433 times.
✓ Branch 1 taken 125970789 times.
✓ Branch 2 taken 521716999 times.
✓ Branch 3 taken 283569434 times.
931257222 while (*p && my_isspace(charset_info, *p)) p++;
7718 409540223 command->first_argument = p;
7719
7720 409540223 command->end = strend(command->query);
7721 409540223 command->query_len = (command->end - command->query);
7722 409540223 parser.read_lines++;
7723 409540223 return 0;
7724 1824062889 }
7725
7726 static struct my_option my_long_options[] = {
7727 #include "caching_sha2_passwordopt-longopts.h"
7728 #include "sslopt-longopts.h"
7729 {"basedir", 'b', "Basedir for tests.", &opt_basedir, &opt_basedir, nullptr,
7730 GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7731 {"character-sets-dir", OPT_CHARSETS_DIR,
7732 "Directory for character set files.", &opt_charsets_dir, &opt_charsets_dir,
7733 nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7734 {"colored-diff", OPT_COLORED_DIFF, "Colorize the diff outout.",
7735 &opt_colored_diff, &opt_colored_diff, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7736 nullptr, 0, nullptr},
7737 {"compress", 'C', "Use the compressed server/client protocol.",
7738 &opt_compress, &opt_compress, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr,
7739 0, nullptr},
7740 {"connect_timeout", OPT_CONNECT_TIMEOUT,
7741 "Number of seconds before connection timeout.", &opt_connect_timeout,
7742 &opt_connect_timeout, nullptr, GET_UINT, REQUIRED_ARG, 120, 0, 3600 * 12,
7743 nullptr, 0, nullptr},
7744 {"cursor-protocol", OPT_CURSOR_PROTOCOL,
7745 "Use cursors for prepared statements.", &cursor_protocol, &cursor_protocol,
7746 nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7747 {"database", 'D', "Database to use.", &opt_db, &opt_db, nullptr, GET_STR,
7748 REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7749 #ifdef NDEBUG
7750 {"debug", '#', "This is a non-debug version. Catch this and exit.", nullptr,
7751 nullptr, nullptr, GET_DISABLED, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
7752 {"debug-check", OPT_DEBUG_CHECK,
7753 "This is a non-debug version. Catch this and exit.", nullptr, nullptr,
7754 nullptr, GET_DISABLED, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7755 {"debug-info", OPT_DEBUG_INFO,
7756 "This is a non-debug version. Catch this and exit.", nullptr, nullptr,
7757 nullptr, GET_DISABLED, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7758 #else
7759 {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", nullptr,
7760 nullptr, nullptr, GET_STR, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
7761 {"debug-check", OPT_DEBUG_CHECK,
7762 "Check memory and open file usage at exit.", &debug_check_flag,
7763 &debug_check_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
7764 nullptr},
7765 {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
7766 &debug_info_flag, &debug_info_flag, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7767 nullptr, 0, nullptr},
7768 #endif
7769 {"default-character-set", OPT_DEFAULT_CHARSET,
7770 "Set the default character set.", &default_charset, &default_charset,
7771 nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7772 {"explain-protocol", OPT_EXPLAIN_PROTOCOL,
7773 "Explain all SELECT/INSERT/REPLACE/UPDATE/DELETE statements",
7774 &explain_protocol, &explain_protocol, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7775 nullptr, 0, nullptr},
7776 {"help", '?', "Display this help and exit.", nullptr, nullptr, nullptr,
7777 GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7778 {"host", 'h', "Connect to host.", &opt_host, &opt_host, nullptr, GET_STR,
7779 REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7780 {"hypergraph", OPT_HYPERGRAPH,
7781 "Force all queries to be run under the hypergraph optimizer.",
7782 &opt_hypergraph, &opt_hypergraph, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7783 nullptr, 0, nullptr},
7784 {"include", 'i', "Include SQL before each test case.", &opt_include,
7785 &opt_include, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
7786 nullptr},
7787 {"json-explain-protocol", OPT_JSON_EXPLAIN_PROTOCOL,
7788 "Explain all SELECT/INSERT/REPLACE/UPDATE/DELETE statements with "
7789 "FORMAT=JSON",
7790 &json_explain_protocol, &json_explain_protocol, nullptr, GET_BOOL, NO_ARG,
7791 0, 0, 0, nullptr, 0, nullptr},
7792 {"logdir", OPT_LOG_DIR, "Directory for log files", &opt_logdir, &opt_logdir,
7793 nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7794 {"mark-progress", OPT_MARK_PROGRESS,
7795 "Write line number and elapsed time to <testname>.progress.",
7796 &opt_mark_progress, &opt_mark_progress, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7797 nullptr, 0, nullptr},
7798 {"init-command", OPT_INIT_COMMAND,
7799 "SQL Command to execute when connecting to MySQL server. Will "
7800 "automatically be re-executed when reconnecting.",
7801 &opt_init_command, &opt_init_command, nullptr, GET_STR, REQUIRED_ARG, 0, 0,
7802 0, nullptr, 0, nullptr},
7803 {"max-connect-retries", OPT_MAX_CONNECT_RETRIES,
7804 "Maximum number of attempts to connect to server.",
7805 &opt_max_connect_retries, &opt_max_connect_retries, nullptr, GET_INT,
7806 REQUIRED_ARG, 500, 1, 10000, nullptr, 0, nullptr},
7807 {"max-connections", OPT_MAX_CONNECTIONS,
7808 "Max number of open connections to server", &opt_max_connections,
7809 &opt_max_connections, nullptr, GET_INT, REQUIRED_ARG, DEFAULT_MAX_CONN, 8,
7810 9120, nullptr, 0, nullptr},
7811 {"no-skip", OPT_NO_SKIP, "Force the test to run without skip.", &no_skip,
7812 &no_skip, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7813 {"no-skip-exclude-list", 'n',
7814 "Contains comma-separated list of to be excluded inc files.",
7815 &excluded_string, &excluded_string, nullptr, GET_STR, REQUIRED_ARG, 0, 0,
7816 0, nullptr, 0, nullptr},
7817 {"offload-count-file", OPT_OFFLOAD_COUNT_FILE, "Offload count report file",
7818 &opt_offload_count_file, &opt_offload_count_file, nullptr, GET_STR,
7819 REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7820 {"opt-trace-protocol", OPT_TRACE_PROTOCOL,
7821 "Trace DML statements with optimizer trace", &opt_trace_protocol,
7822 &opt_trace_protocol, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
7823 nullptr},
7824 {"password", 'p', "Password to use when connecting to server.", nullptr,
7825 nullptr, nullptr, GET_STR, OPT_ARG, 0, 0, 0, nullptr, 0, nullptr},
7826 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
7827 &opt_plugin_dir, &opt_plugin_dir, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0,
7828 nullptr, 0, nullptr},
7829 {"port", 'P',
7830 "Port number to use for connection or 0 for default to, in "
7831 "order of preference, my.cnf, $MYSQL_TCP_PORT, "
7832 #if MYSQL_PORT_DEFAULT == 0
7833 "/etc/services, "
7834 #endif
7835 "built-in default (" STRINGIFY_ARG(MYSQL_PORT) ").",
7836 &opt_port, &opt_port, nullptr, GET_INT, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
7837 nullptr},
7838 {"protocol", OPT_MYSQL_PROTOCOL,
7839 "The protocol of connection (tcp,socket,pipe,memory).", nullptr, nullptr,
7840 nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7841 {"ps-protocol", OPT_PS_PROTOCOL,
7842 "Use prepared-statement protocol for communication.", &ps_protocol,
7843 &ps_protocol, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7844 {"quiet", 's', "Suppress all normal output.", &silent, &silent, nullptr,
7845 GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7846 {"record", 'r', "Record output of test_file into result file.", nullptr,
7847 nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7848 {"result-file", 'R', "Read/store result from/in this file.",
7849 &result_file_name, &result_file_name, nullptr, GET_STR, REQUIRED_ARG, 0, 0,
7850 0, nullptr, 0, nullptr},
7851 {"result-format-version", OPT_RESULT_FORMAT_VERSION,
7852 "Version of the result file format to use", &opt_result_format_version,
7853 &opt_result_format_version, nullptr, GET_INT, REQUIRED_ARG, 1, 1, 2,
7854 nullptr, 0, nullptr},
7855 #ifdef _WIN32
7856 {"safe-process-pid", OPT_SAFEPROCESS_PID, "PID of safeprocess.",
7857 &opt_safe_process_pid, &opt_safe_process_pid, 0, GET_INT, REQUIRED_ARG, 0,
7858 0, 0, 0, 0, 0},
7859 #endif
7860 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
7861 "Base name of shared memory.", &shared_memory_base_name,
7862 &shared_memory_base_name, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr,
7863 0, nullptr},
7864 {"silent", 's', "Suppress all normal output. Synonym for --quiet.", &silent,
7865 &silent, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7866 {"socket", 'S', "The socket file to use for connection.", &unix_sock,
7867 &unix_sock, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7868 {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select.",
7869 &sp_protocol, &sp_protocol, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
7870 nullptr},
7871 {"tail-lines", OPT_TAIL_LINES,
7872 "Number of lines of the result to include in a failure report.",
7873 &opt_tail_lines, &opt_tail_lines, nullptr, GET_INT, REQUIRED_ARG, 0, 0,
7874 10000, nullptr, 0, nullptr},
7875 {"test-file", 'x', "Read test from/in this file (default stdin).", nullptr,
7876 nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7877 {"timer-file", 'm', "File where the timing in microseconds is stored.",
7878 nullptr, nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0,
7879 nullptr},
7880 {"tmpdir", 't', "Temporary directory where sockets are put.", nullptr,
7881 nullptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7882 {"trace-exec", OPT_TRACE_EXEC, "Print output from exec to stdout.",
7883 &trace_exec, &trace_exec, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
7884 nullptr},
7885 {"user", 'u', "User for login.", &opt_user, &opt_user, nullptr, GET_STR,
7886 REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7887 {"verbose", 'v', "Write more.", &verbose, &verbose, nullptr, GET_BOOL,
7888 NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7889 {"version", 'V', "Output version information and exit.", nullptr, nullptr,
7890 nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0, nullptr, 0, nullptr},
7891 {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select.",
7892 &view_protocol, &view_protocol, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7893 nullptr, 0, nullptr},
7894 {"async-client", '*', "Use async client.", &use_async_client,
7895 &use_async_client, nullptr, GET_BOOL, NO_ARG, 0, 0, 0, nullptr, 0,
7896 nullptr},
7897 {"compression-algorithms", 0,
7898 "Use compression algorithm in server/client protocol. Valid values "
7899 "are any combination of 'zstd','zlib','uncompressed'.",
7900 &opt_compress_algorithm, &opt_compress_algorithm, nullptr, GET_STR,
7901 REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr},
7902 {"zstd-compression-level", 0,
7903 "Use this compression level in the client/server protocol, in case "
7904 "--compression-algorithms=zstd. Valid range is between 1 and 22, "
7905 "inclusive. Default is 3.",
7906 &opt_zstd_compress_level, &opt_zstd_compress_level, nullptr, GET_UINT,
7907 REQUIRED_ARG, 3, 1, 22, nullptr, 0, nullptr},
7908 {"test-ssl-fips-mode", 0,
7909 "Toggle SSL FIPS mode on or off, to see whether FIPS is supported. "
7910 "Prints the result to stdout, and then exits. "
7911 "Used by mtr to enable/disable FIPS tests. ",
7912 &opt_test_ssl_fips_mode, nullptr, nullptr, GET_BOOL, NO_ARG, 0, 0, 0,
7913 nullptr, 0, nullptr},
7914
7915 {nullptr, 0, nullptr, nullptr, nullptr, nullptr, GET_NO_ARG, NO_ARG, 0, 0,
7916 0, nullptr, 0, nullptr}};
7917
7918 6 static void usage() {
7919 6 print_version();
7920 6 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
7921 6 printf(
7922 "Runs a test against the mysql server and compares output with a results "
7923 "file.\n\n");
7924 6 printf("Usage: %s [OPTIONS] [database] < test_file\n", my_progname);
7925 6 my_print_help(my_long_options);
7926 6 printf(
7927 " --no-defaults Don't read default options from any options "
7928 "file.\n");
7929 6 my_print_variables(my_long_options);
7930 6 }
7931
7932 843866 static bool get_one_option(int optid, const struct my_option *opt,
7933 char *argument) {
7934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 843866 times.
843866 if (opt_test_ssl_fips_mode) {
7935 char ssl_err_string[OPENSSL_ERROR_LENGTH] = {'\0'};
7936 int fips_test = test_ssl_fips_mode(ssl_err_string);
7937 fprintf(stdout, "--test-ssl-fips-mode %d %s\n", fips_test,
7938 fips_test == 0 ? ssl_err_string : "Success");
7939 exit(0);
7940 }
7941
13/16
✗ Branch 0 not taken.
✓ Branch 1 taken 13743 times.
✓ Branch 2 taken 49415 times.
✓ Branch 3 taken 10478 times.
✓ Branch 4 taken 89792 times.
✓ Branch 5 taken 50168 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 22 times.
✓ Branch 8 taken 52 times.
✓ Branch 9 taken 10478 times.
✓ Branch 10 taken 50135 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 569575 times.
843866 switch (optid) {
7942 case '#':
7943 #ifndef NDEBUG
7944 DBUG_PUSH(argument ? argument : "d:t:S:i:O,/tmp/mysqltest.trace");
7945 debug_check_flag = true;
7946 #endif
7947 break;
7948 13743 case 'r':
7949 13743 record = 1;
7950 13743 break;
7951 49415 case 'x': {
7952 char buff[FN_REFLEN];
7953
3/4
✓ Branch 0 taken 49415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39660 times.
✓ Branch 3 taken 9755 times.
49415 if (!test_if_hard_path(argument)) {
7954
1/2
✓ Branch 0 taken 39660 times.
✗ Branch 1 not taken.
39660 strxmov(buff, opt_basedir, argument, NullS);
7955 39660 argument = buff;
7956 }
7957
1/2
✓ Branch 0 taken 49415 times.
✗ Branch 1 not taken.
49415 fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
7958
2/4
✓ Branch 0 taken 49415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49415 times.
✗ Branch 3 not taken.
49415 assert(cur_file == file_stack && cur_file->file == nullptr);
7959
3/4
✓ Branch 0 taken 49415 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 49412 times.
49415 if (!(cur_file->file = fopen(buff, "rb")))
7960 3 die("Could not open '%s' for reading, errno: %d", buff, errno);
7961
1/2
✓ Branch 0 taken 49412 times.
✗ Branch 1 not taken.
49412 cur_file->file_name = my_strdup(PSI_NOT_INSTRUMENTED, buff, MYF(MY_FAE));
7962 49412 cur_file->lineno = 1;
7963 49412 break;
7964 }
7965 10478 case 'm': {
7966 static char buff[FN_REFLEN];
7967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10478 times.
10478 if (!test_if_hard_path(argument)) {
7968 strxmov(buff, opt_basedir, argument, NullS);
7969 argument = buff;
7970 }
7971 10478 fn_format(buff, argument, "", "", MY_UNPACK_FILENAME);
7972 10478 timer_file = buff;
7973 10478 unlink(timer_file); /* Ignore error, may not exist */
7974 10478 break;
7975 }
7976 89792 case 'p':
7977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89792 times.
89792 if (argument == disabled_my_option) {
7978 // Don't require password
7979 static char empty_password[] = {'\0'};
7980 assert(empty_password[0] ==
7981 '\0'); // Check that it has not been overwritten
7982 argument = empty_password;
7983 }
7984
1/2
✓ Branch 0 taken 89792 times.
✗ Branch 1 not taken.
89792 if (argument) {
7985 89792 my_free(opt_pass);
7986 89792 opt_pass = my_strdup(PSI_NOT_INSTRUMENTED, argument, MYF(MY_FAE));
7987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89792 times.
89792 while (*argument) *argument++ = 'x'; /* Destroy argument */
7988 89792 tty_password = false;
7989 } else
7990 tty_password = true;
7991 89792 break;
7992 #include "sslopt-case.h"
7993
7994 10478 case 't':
7995 10478 my_stpnmov(TMPDIR, argument, sizeof(TMPDIR));
7996 10478 break;
7997 50135 case OPT_LOG_DIR:
7998 /* Check that the file exists */
7999
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50135 times.
50135 if (access(opt_logdir, F_OK) != 0)
8000 die("The specified log directory does not exist: '%s'", opt_logdir);
8001 50135 break;
8002 case OPT_RESULT_FORMAT_VERSION:
8003 set_result_format_version(opt_result_format_version);
8004 break;
8005 3 case 'V':
8006 3 print_version();
8007 3 exit(0);
8008 2 case OPT_MYSQL_PROTOCOL:
8009 2 opt_protocol =
8010 2 find_type_or_exit(argument, &sql_protocol_typelib, opt->name);
8011 2 break;
8012 3 case '?':
8013 3 usage();
8014 3 exit(0);
8015 }
8016 843857 return false;
8017 }
8018
8019 /**
8020 Test case or the result file names may use alphanumeric characters
8021 (A-Z, a-z, 0-9), dash ('-') or underscore ('_'), but should not
8022 start with dash or underscore.
8023
8024 Check if a file name contains any other special characters. If yes,
8025 throw an error and abort the test run.
8026
8027 @param[in] file_name File name
8028 */
8029
8030 85519 static void validate_filename(const char *file_name) {
8031 85519 const char *fname = strrchr(file_name, '/');
8032
8033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 85519 times.
85519 if (fname == nullptr) {
8034 if (is_windows) {
8035 fname = strrchr(file_name, '\\');
8036
8037 if (fname == nullptr)
8038 fname = file_name;
8039 else
8040 fname++;
8041 } else
8042 fname = file_name;
8043 } else
8044 85519 fname++;
8045
8046 85519 file_name = fname;
8047
8048 // Check if first character in the file name is a alphanumeric character
8049
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 85513 times.
85519 if (!my_isalnum(charset_info, file_name[0])) {
8050 6 die("Invalid file name '%s', first character must be alpha-numeric.",
8051 file_name);
8052 } else
8053 85513 file_name++;
8054
8055 // Skip extension('.test' or '.result' or '.inc' etc) in the file name
8056 85513 const char *file_name_end = strrchr(file_name, '.');
8057
8058
3/4
✓ Branch 0 taken 1379569 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1294062 times.
✓ Branch 3 taken 85507 times.
1379569 while (*file_name && (file_name != file_name_end) &&
8059
4/4
✓ Branch 0 taken 67005 times.
✓ Branch 1 taken 1227057 times.
✓ Branch 2 taken 82499 times.
✓ Branch 3 taken 1144558 times.
1294062 (file_name[0] == '-' || file_name[0] == '_' ||
8060 #ifdef WITH_WSREP
8061 /* PXC/Galera has test-case name with # character.
8062 Allow it for now */
8063
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 1144491 times.
1144558 file_name[0] == '#' ||
8064 #endif /* WITH_WSREP */
8065
2/2
✓ Branch 0 taken 1144485 times.
✓ Branch 1 taken 6 times.
1144491 my_isalnum(charset_info, file_name[0]))) {
8066 1294056 file_name++;
8067 }
8068
8069
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 85507 times.
85513 if (file_name != file_name_end) {
8070 6 die("Invalid file name '%s'. Test or result file name should "
8071 "consist of only alpha-numeric characters, dash (-), "
8072 "underscore (_) or hash (#), but should not start with dash or "
8073 "underscore or hash.",
8074 fname);
8075 }
8076 85507 }
8077
8078 50135 static int parse_args(int argc, char **argv) {
8079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50135 times.
50135 if (load_defaults("my", load_default_groups, &argc, &argv, &argv_alloc))
8080 exit(1);
8081
8082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50126 times.
50135 if ((handle_options(&argc, &argv, my_long_options, get_one_option))) exit(1);
8083
8084 // Check for special characters in test case file name
8085
2/2
✓ Branch 0 taken 49412 times.
✓ Branch 1 taken 714 times.
50126 if (cur_file->file_name) validate_filename(cur_file->file_name);
8086
8087 // Check for special characters in result file name
8088
2/2
✓ Branch 0 taken 36107 times.
✓ Branch 1 taken 14007 times.
50114 if (result_file_name) validate_filename(result_file_name);
8089
8090
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 50111 times.
50114 if (argc > 1) {
8091 3 usage();
8092 3 exit(1);
8093 }
8094
8095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (argc == 1) opt_db = *argv;
8096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (tty_password) opt_pass = get_tty_password(NullS);
8097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (debug_info_flag) my_end_arg = MY_CHECK_ERROR | MY_GIVE_INFO;
8098
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (debug_check_flag) my_end_arg = MY_CHECK_ERROR;
8099
8100
2/2
✓ Branch 0 taken 36368 times.
✓ Branch 1 taken 13743 times.
50111 if (!record) {
8101 /* Check that the result file exists */
8102
4/6
✓ Branch 0 taken 22364 times.
✓ Branch 1 taken 14004 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22364 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 36368 times.
36368 if (result_file_name && access(result_file_name, F_OK) != 0)
8103 die("The specified result file '%s' does not exist", result_file_name);
8104 }
8105
8106 50111 return 0;
8107 }
8108
8109 /*
8110 Write the content of str into file
8111
8112 SYNOPSIS
8113 str_to_file2
8114 fname - name of file to truncate/create and write to
8115 str - content to write to file
8116 size - size of content witten to file
8117 append - append to file instead of overwriting old file
8118 */
8119
8120 344012 void str_to_file2(const char *fname, char *str, size_t size, bool append) {
8121 int fd;
8122 char buff[FN_REFLEN];
8123 344012 int flags = O_WRONLY | O_CREAT;
8124
2/4
✓ Branch 0 taken 344012 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 344012 times.
344012 if (!test_if_hard_path(fname)) {
8125 strxmov(buff, opt_basedir, fname, NullS);
8126 fname = buff;
8127 }
8128
1/2
✓ Branch 0 taken 344012 times.
✗ Branch 1 not taken.
344012 fn_format(buff, fname, "", "", MY_UNPACK_FILENAME);
8129
8130
2/2
✓ Branch 0 taken 77546 times.
✓ Branch 1 taken 266466 times.
344012 if (!append) flags |= O_TRUNC;
8131
2/4
✓ Branch 0 taken 344012 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 344012 times.
344012 if ((fd = my_open(buff, flags, MYF(MY_WME))) < 0)
8132 die("Could not open '%s' for writing, errno: %d", buff, errno);
8133
5/8
✓ Branch 0 taken 266466 times.
✓ Branch 1 taken 77546 times.
✓ Branch 2 taken 266466 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 266466 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 344012 times.
344012 if (append && my_seek(fd, 0, SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
8134 die("Could not find end of file '%s', errno: %d", buff, errno);
8135
2/4
✓ Branch 0 taken 344012 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 344012 times.
344012 if (my_write(fd, (uchar *)str, size, MYF(MY_WME | MY_FNABP)))
8136 die("write failed, errno: %d", errno);
8137
1/2
✓ Branch 0 taken 344012 times.
✗ Branch 1 not taken.
344012 my_close(fd, MYF(0));
8138 344012 }
8139
8140 /*
8141 Write the content of str into file
8142
8143 SYNOPSIS
8144 str_to_file
8145 fname - name of file to truncate/create and write to
8146 str - content to write to file
8147 size - size of content witten to file
8148 */
8149
8150 49493 void str_to_file(const char *fname, char *str, size_t size) {
8151 49493 str_to_file2(fname, str, size, false);
8152 49493 }
8153
8154 #ifdef _WIN32
8155
8156 typedef Prealloced_array<const char *, 16> Patterns;
8157 Patterns *patterns;
8158
8159 /*
8160 init_win_path_patterns
8161
8162 DESCRIPTION
8163 Setup string patterns that will be used to detect filenames that
8164 needs to be converted from Win to Unix format
8165
8166 */
8167
8168 void init_win_path_patterns() {
8169 /* List of string patterns to match in order to find paths */
8170 const char *paths[] = {
8171 "$MYSQL_TEST_DIR", "$MYSQL_TMP_DIR", "$MYSQLTEST_VARDIR",
8172 "$MASTER_MYSOCK", "$MYSQL_SHAREDIR", "$MYSQL_CHARSETSDIR",
8173 "$MYSQL_LIBDIR", "./test/", ".ibd",
8174 ".\\ibdata", ".\\ibtmp", ".\\undo"};
8175 int num_paths = sizeof(paths) / sizeof(char *);
8176 int i;
8177 char *p;
8178
8179 DBUG_TRACE;
8180
8181 patterns = new Patterns(PSI_NOT_INSTRUMENTED);
8182
8183 /* Loop through all paths in the array */
8184 for (i = 0; i < num_paths; i++) {
8185 VAR *v;
8186 if (*(paths[i]) == '$') {
8187 v = var_get(paths[i], 0, 0, 0);
8188 p = my_strdup(PSI_NOT_INSTRUMENTED, v->str_val, MYF(MY_FAE));
8189 } else
8190 p = my_strdup(PSI_NOT_INSTRUMENTED, paths[i], MYF(MY_FAE));
8191
8192 /* Don't insert zero length strings in patterns array */
8193 if (std::strlen(p) == 0) {
8194 my_free(p);
8195 continue;
8196 }
8197
8198 if (patterns->push_back(p)) die("Out of memory");
8199
8200 DBUG_PRINT("info", ("p: %s", p));
8201 while (*p) {
8202 if (*p == '/') *p = '\\';
8203 p++;
8204 }
8205 }
8206 }
8207
8208 void free_win_path_patterns() {
8209 uint i = 0;
8210 const char **pat;
8211 for (pat = patterns->begin(); pat != patterns->end(); ++pat) {
8212 my_free(const_cast<char *>(*pat));
8213 }
8214 delete patterns;
8215 patterns = NULL;
8216 }
8217
8218 /*
8219 fix_win_paths
8220
8221 DESCRIPTION
8222 Search the string 'val' for the patterns that are known to be
8223 strings that contain filenames. Convert all \ to / in the
8224 filenames that are found.
8225
8226 Ex:
8227 val = 'Error "c:\mysql\mysql-test\var\test\t1.frm" didn't exist'
8228 => $MYSQL_TEST_DIR is found by strstr
8229 => all \ from c:\mysql\m... until next space is converted into /
8230 */
8231
8232 void fix_win_paths(const char *val, size_t len) {
8233 DBUG_TRACE;
8234 const char **pat;
8235 for (pat = patterns->begin(); pat != patterns->end(); ++pat) {
8236 char *p;
8237 DBUG_PRINT("info", ("pattern: %s", *pat));
8238
8239 /* Find and fix each path in this string */
8240 p = const_cast<char *>(val);
8241 while (p = strstr(p, *pat)) {
8242 DBUG_PRINT("info", ("Found %s in val p: %s", *pat, p));
8243 /* Found the pattern. Back up to the start of this path */
8244 while (p > val && !my_isspace(charset_info, *(p - 1))) {
8245 p--;
8246 }
8247
8248 while (*p && !my_isspace(charset_info, *p)) {
8249 if (*p == '\\') *p = '/';
8250 p++;
8251 }
8252 DBUG_PRINT("info", ("Converted \\ to / in %s", val));
8253 }
8254 }
8255 DBUG_PRINT("exit", (" val: %s, len: %d", val, len));
8256 }
8257 #endif
8258
8259 /*
8260 Append the result for one field to the dynamic string ds
8261 */
8262
8263 236482559 static void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD *field,
8264 char *val, size_t len, bool is_null) {
8265 236482559 char null[] = "NULL";
8266
8267
4/4
✓ Branch 0 taken 344998 times.
✓ Branch 1 taken 236137561 times.
✓ Branch 2 taken 159980 times.
✓ Branch 3 taken 185018 times.
236482559 if (col_idx < max_replace_column && replace_column[col_idx]) {
8268 159980 val = replace_column[col_idx];
8269 159980 len = std::strlen(val);
8270
2/2
✓ Branch 0 taken 34388745 times.
✓ Branch 1 taken 201933834 times.
236322579 } else if (is_null) {
8271 34388745 val = null;
8272 34388745 len = 4;
8273 }
8274 #ifdef _WIN32
8275 else if ((field->type == MYSQL_TYPE_DOUBLE ||
8276 field->type == MYSQL_TYPE_FLOAT) &&
8277 field->decimals >= 31) {
8278 /* Convert 1.2e+018 to 1.2e+18 and 1.2e-018 to 1.2e-18 */
8279 char *start = strchr(val, 'e');
8280 if (start && std::strlen(start) >= 5 &&
8281 (start[1] == '-' || start[1] == '+') && start[2] == '0') {
8282 start += 2; /* Now points at first '0' */
8283 if (field->flags & ZEROFILL_FLAG) {
8284 /* Move all chars before the first '0' one step right */
8285 memmove(val + 1, val, start - val);
8286 *val = '0';
8287 } else {
8288 /* Move all chars after the first '0' one step left */
8289 memmove(start, start + 1, std::strlen(start));
8290 len--;
8291 }
8292 }
8293 }
8294 #endif
8295
8296
2/2
✓ Branch 0 taken 236168113 times.
✓ Branch 1 taken 314446 times.
236482559 if (!display_result_vertically) {
8297
3/4
✓ Branch 0 taken 184116328 times.
✓ Branch 1 taken 52051785 times.
✓ Branch 2 taken 184116328 times.
✗ Branch 3 not taken.
236168113 if (col_idx) dynstr_append_mem(ds, "\t", 1);
8298
1/2
✓ Branch 0 taken 236168113 times.
✗ Branch 1 not taken.
236168113 replace_dynstr_append_mem(ds, val, len);
8299 } else {
8300
1/2
✓ Branch 0 taken 314446 times.
✗ Branch 1 not taken.
314446 dynstr_append(ds, field->name);
8301
1/2
✓ Branch 0 taken 314446 times.
✗ Branch 1 not taken.
314446 dynstr_append_mem(ds, "\t", 1);
8302
1/2
✓ Branch 0 taken 314446 times.
✗ Branch 1 not taken.
314446 replace_dynstr_append_mem(ds, val, len);
8303
1/2
✓ Branch 0 taken 314446 times.
✗ Branch 1 not taken.
314446 dynstr_append_mem(ds, "\n", 1);
8304 }
8305 236482559 }
8306
8307 /*
8308 Append all results to the dynamic string separated with '\t'
8309 Values may be converted with 'replace_column'
8310 */
8311
8312 1129149 static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) {
8313 MYSQL_ROW row;
8314 1129149 uint num_fields = mysql_num_fields(res);
8315 1129149 MYSQL_FIELD *fields = mysql_fetch_fields(res);
8316 ulong *lengths;
8317
8318
2/2
✓ Branch 0 taken 52060828 times.
✓ Branch 1 taken 1129149 times.
53189977 while ((row = mysql_fetch_row_wrapper(res))) {
8319 uint i;
8320 52060828 lengths = mysql_fetch_lengths(res);
8321
2/2
✓ Branch 0 taken 236482559 times.
✓ Branch 1 taken 52060828 times.
288543387 for (i = 0; i < num_fields; i++) {
8322 /* looks ugly , but put here to convince parfait */
8323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236482559 times.
236482559 assert(lengths);
8324 236482559 append_field(ds, i, &fields[i], row[i], lengths[i], !row[i]);
8325 }
8326
2/2
✓ Branch 0 taken 52051785 times.
✓ Branch 1 taken 9043 times.
52060828 if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1);
8327 }
8328 1129149 }
8329
8330 /*
8331 Append all results from ps execution to the dynamic string separated
8332 with '\t'. Values may be converted with 'replace_column'
8333 */
8334
8335 static void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
8336 MYSQL_FIELD *fields, uint num_fields) {
8337 MYSQL_BIND *my_bind;
8338 bool *is_null;
8339 ulong *length;
8340 uint i;
8341
8342 /* Allocate array with bind structs, lengths and NULL flags */
8343 my_bind = (MYSQL_BIND *)my_malloc(PSI_NOT_INSTRUMENTED,
8344 num_fields * sizeof(MYSQL_BIND),
8345 MYF(MY_WME | MY_FAE | MY_ZEROFILL));
8346 length = (ulong *)my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(ulong),
8347 MYF(MY_WME | MY_FAE));
8348 is_null = (bool *)my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(bool),
8349 MYF(MY_WME | MY_FAE));
8350
8351 /* Allocate data for the result of each field */
8352 for (i = 0; i < num_fields; i++) {
8353 size_t max_length = fields[i].max_length + 1;
8354 my_bind[i].buffer_type = MYSQL_TYPE_STRING;
8355 my_bind[i].buffer =
8356 my_malloc(PSI_NOT_INSTRUMENTED, max_length, MYF(MY_WME | MY_FAE));
8357 my_bind[i].buffer_length = static_cast<ulong>(max_length);
8358 my_bind[i].is_null = &is_null[i];
8359 my_bind[i].length = &length[i];
8360
8361 DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %lu", i,
8362 my_bind[i].buffer_type, my_bind[i].buffer_length));
8363 }
8364
8365 if (mysql_stmt_bind_result(stmt, my_bind))
8366 die("mysql_stmt_bind_result failed: %d: %s", mysql_stmt_errno(stmt),
8367 mysql_stmt_error(stmt));
8368
8369 while (mysql_stmt_fetch(stmt) == 0) {
8370 for (i = 0; i < num_fields; i++)
8371 append_field(ds, i, &fields[i], (char *)my_bind[i].buffer,
8372 *my_bind[i].length, *my_bind[i].is_null);
8373 if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1);
8374 }
8375
8376 int rc;
8377 if ((rc = mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA)
8378 die("fetch didn't end with MYSQL_NO_DATA from statement: %d: %s; rc=%d",
8379 mysql_stmt_errno(stmt), mysql_stmt_error(stmt), rc);
8380
8381 for (i = 0; i < num_fields; i++) {
8382 /* Free data for output */
8383 my_free(my_bind[i].buffer);
8384 }
8385 /* Free array with bind structs, lengths and NULL flags */
8386 my_free(my_bind);
8387 my_free(length);
8388 my_free(is_null);
8389 }
8390
8391 /*
8392 Append metadata for fields to output
8393 */
8394
8395 297 static void append_metadata(DYNAMIC_STRING *ds, MYSQL_FIELD *field,
8396 uint num_fields) {
8397 MYSQL_FIELD *field_end;
8398 297 dynstr_append(ds,
8399 "Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
8400 "Column_alias\tType\tLength\tMax length\tIs_null\t"
8401 "Flags\tDecimals\tCharsetnr\n");
8402
8403
2/2
✓ Branch 0 taken 3488 times.
✓ Branch 1 taken 297 times.
3785 for (field_end = field + num_fields; field < field_end; field++) {
8404 3488 dynstr_append_mem(ds, field->catalog, field->catalog_length);
8405 3488 dynstr_append_mem(ds, "\t", 1);
8406 3488 dynstr_append_mem(ds, field->db, field->db_length);
8407 3488 dynstr_append_mem(ds, "\t", 1);
8408 3488 dynstr_append_mem(ds, field->org_table, field->org_table_length);
8409 3488 dynstr_append_mem(ds, "\t", 1);
8410 3488 dynstr_append_mem(ds, field->table, field->table_length);
8411 3488 dynstr_append_mem(ds, "\t", 1);
8412 3488 dynstr_append_mem(ds, field->org_name, field->org_name_length);
8413 3488 dynstr_append_mem(ds, "\t", 1);
8414 3488 dynstr_append_mem(ds, field->name, field->name_length);
8415 3488 dynstr_append_mem(ds, "\t", 1);
8416 3488 replace_dynstr_append_uint(ds, field->type);
8417 3488 dynstr_append_mem(ds, "\t", 1);
8418 3488 replace_dynstr_append_uint(ds, field->length);
8419 3488 dynstr_append_mem(ds, "\t", 1);
8420 3488 replace_dynstr_append_uint(ds, field->max_length);
8421 3488 dynstr_append_mem(ds, "\t", 1);
8422
2/2
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 3202 times.
3488 dynstr_append_mem(ds, (IS_NOT_NULL(field->flags) ? "N" : "Y"), 1);
8423 3488 dynstr_append_mem(ds, "\t", 1);
8424 3488 replace_dynstr_append_uint(ds, field->flags);
8425 3488 dynstr_append_mem(ds, "\t", 1);
8426 3488 replace_dynstr_append_uint(ds, field->decimals);
8427 3488 dynstr_append_mem(ds, "\t", 1);
8428 3488 replace_dynstr_append_uint(ds, field->charsetnr);
8429 3488 dynstr_append_mem(ds, "\n", 1);
8430 }
8431 297 }
8432
8433 /*
8434 Append affected row count and other info to output
8435 */
8436
8437 3142 static void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows,
8438 const char *info) {
8439 char buf[40], buff2[21];
8440
1/2
✓ Branch 0 taken 3142 times.
✗ Branch 1 not taken.
3142 sprintf(buf, "affected rows: %s\n", llstr(affected_rows, buff2));
8441
1/2
✓ Branch 0 taken 3142 times.
✗ Branch 1 not taken.
3142 dynstr_append(ds, buf);
8442
2/2
✓ Branch 0 taken 1733 times.
✓ Branch 1 taken 1409 times.
3142 if (info) {
8443
1/2
✓ Branch 0 taken 1733 times.
✗ Branch 1 not taken.
1733 dynstr_append(ds, "info: ");
8444
1/2
✓ Branch 0 taken 1733 times.
✗ Branch 1 not taken.
1733 dynstr_append(ds, info);
8445
1/2
✓ Branch 0 taken 1733 times.
✗ Branch 1 not taken.
1733 dynstr_append_mem(ds, "\n", 1);
8446 }
8447 3142 }
8448
8449 /**
8450 @brief Append state change information (received through Ok packet) to the
8451 output.
8452
8453 @param [in,out] ds Dynamic string to hold the content to be printed.
8454 @param [in] mysql Connection handle.
8455 */
8456
8457 588 static void append_session_track_info(DYNAMIC_STRING *ds, MYSQL *mysql) {
8458
2/2
✓ Branch 0 taken 3528 times.
✓ Branch 1 taken 588 times.
4116 for (unsigned int type = SESSION_TRACK_BEGIN; type <= SESSION_TRACK_END;
8459 type++) {
8460 const char *data;
8461 size_t data_length;
8462
8463
3/4
✓ Branch 0 taken 3528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 387 times.
✓ Branch 3 taken 3141 times.
3528 if (!mysql_session_track_get_first(mysql, (enum_session_state_type)type,
8464 &data, &data_length)) {
8465 /*
8466 Append the type information. Please update the definition of APPEND_TYPE
8467 when any changes are made to enum_session_state_type.
8468 */
8469
13/23
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 86 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 78 times.
✓ Branch 7 taken 125 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 53 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 16 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 86 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 29 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 78 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 125 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
387 APPEND_TYPE(type);
8470
1/2
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
387 dynstr_append(ds, "-- ");
8471
1/2
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
387 dynstr_append_mem(ds, data, data_length);
8472 } else
8473 3141 continue;
8474
3/4
✓ Branch 0 taken 478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 387 times.
478 while (!mysql_session_track_get_next(mysql, (enum_session_state_type)type,
8475 &data, &data_length)) {
8476
1/2
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
91 dynstr_append(ds, "\n-- ");
8477
1/2
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
91 dynstr_append_mem(ds, data, data_length);
8478 }
8479
1/2
✓ Branch 0 taken 387 times.
✗ Branch 1 not taken.
387 dynstr_append(ds, "\n\n");
8480 }
8481 588 }
8482
8483 /*
8484 Display the table headings with the names tab separated
8485 */
8486
8487 1052452 static void append_table_headings(DYNAMIC_STRING *ds, MYSQL_FIELD *field,
8488 uint num_fields) {
8489 uint col_idx;
8490
2/2
✓ Branch 0 taken 6869953 times.
✓ Branch 1 taken 1052452 times.
7922405 for (col_idx = 0; col_idx < num_fields; col_idx++) {
8491
2/2
✓ Branch 0 taken 5817501 times.
✓ Branch 1 taken 1052452 times.
6869953 if (col_idx) dynstr_append_mem(ds, "\t", 1);
8492 6869953 replace_dynstr_append(ds, field[col_idx].name);
8493 }
8494 1052452 dynstr_append_mem(ds, "\n", 1);
8495 1052452 }
8496
8497 /// Check whether a given warning is in list of disabled or enabled warnings.
8498 ///
8499 /// @param warnings List of either disabled or enabled warnings.
8500 /// @param error Error number
8501 /// @param warning_found Boolean value, should be set to true if warning
8502 /// is found in the list, false otherwise.
8503 ///
8504 /// @retval True if the given warning is present in the list, and
8505 /// ignore flag for that warning is not set, false otherwise.
8506 1743 static bool match_warnings(Expected_warnings *warnings, std::uint32_t error,
8507 bool *warning_found) {
8508 1743 bool match_found = false;
8509 1743 std::vector<std::unique_ptr<Warning>>::iterator warning = warnings->begin();
8510
8511
2/2
✓ Branch 0 taken 1971 times.
✓ Branch 1 taken 145 times.
2116 for (; warning != warnings->end(); warning++) {
8512
2/2
✓ Branch 0 taken 1604 times.
✓ Branch 1 taken 367 times.
1971 if ((*warning)->warning_code() == error) {
8513 1604 *warning_found = true;
8514
2/2
✓ Branch 0 taken 1598 times.
✓ Branch 1 taken 6 times.
1604 if (!(*warning)->ignore_warning()) {
8515 1598 match_found = true;
8516 1598 break;
8517 }
8518 }
8519 }
8520
8521 1743 return match_found;
8522 }
8523
8524 /// Handle one warning which occurred during execution of a query.
8525 ///
8526 /// @param ds DYNAMIC_STRING object to store the warnings.
8527 /// @param warning Warning string
8528 ///
8529 /// @retval True if a warning is found in the list of disabled or enabled
8530 /// warnings, false otherwise.
8531 1743 static bool handle_one_warning(DYNAMIC_STRING *ds, std::string warning) {
8532 // Each line of show warnings output contains information about
8533 // error level, error code and the error/warning message separated
8534 // by '\t'. Parse each line from the show warnings output to
8535 // extract the error code and compare it with list of expected
8536 // warnings.
8537 1743 bool warning_found = false;
8538 1743 std::string error_code;
8539
1/2
✓ Branch 0 taken 1743 times.
✗ Branch 1 not taken.
1743 std::stringstream warn_msg(warning);
8540
8541
4/6
✓ Branch 0 taken 6972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6972 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5229 times.
✓ Branch 5 taken 1743 times.
6972 while (std::getline(warn_msg, error_code, '\t')) {
8542
1/2
✓ Branch 0 taken 5229 times.
✗ Branch 1 not taken.
5229 int errcode = get_int_val(error_code.c_str());
8543
2/2
✓ Branch 0 taken 1743 times.
✓ Branch 1 taken 3486 times.
5229 if (errcode != -1) {
8544
2/2
✓ Branch 0 taken 1581 times.
✓ Branch 1 taken 162 times.
1743 if (disabled_warnings->count()) {
8545 // Print the warning if it doesn't match with any of the
8546 // disabled warnings.
8547
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 1493 times.
1581 if (!match_warnings(disabled_warnings, errcode, &warning_found)) {
8548
1/2
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
88 dynstr_append_mem(ds, warning.c_str(), warning.length());
8549
1/2
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
88 dynstr_append_mem(ds, "\n", 1);
8550 }
8551
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
162 } else if (enabled_warnings->count()) {
8552
2/2
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 57 times.
162 if (match_warnings(enabled_warnings, errcode, &warning_found)) {
8553
1/2
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
105 dynstr_append_mem(ds, warning.c_str(), warning.length());
8554
1/2
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
105 dynstr_append_mem(ds, "\n", 1);
8555 }
8556 }
8557 }
8558 }
8559
8560 1743 return warning_found;
8561 1743 }
8562
8563 /// Handle warnings which occurred during execution of a query.
8564 ///
8565 /// @param ds DYNAMIC_STRING object to store the warnings.
8566 /// @param ds_warnings String containing all the generated warnings.
8567 1371 static void handle_warnings(DYNAMIC_STRING *ds, const char *ds_warnings) {
8568 1371 bool warning_found = false;
8569 1371 std::string warning;
8570
2/4
✓ Branch 0 taken 1371 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1371 times.
✗ Branch 3 not taken.
2742 std::stringstream warnings(ds_warnings);
8571
8572 // Set warning_found only if at least one of the warning exist
8573 // in expected list of warnings.
8574
4/6
✓ Branch 0 taken 3114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3114 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1743 times.
✓ Branch 5 taken 1371 times.
3114 while (std::getline(warnings, warning))
8575
4/6
✓ Branch 0 taken 1743 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1743 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1604 times.
✓ Branch 5 taken 139 times.
1743 if (handle_one_warning(ds, warning)) warning_found = true;
8576
8577 // Throw an error and abort the test run if a query generates warnings
8578 // which are not listed as expected.
8579
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1365 times.
1371 if (!warning_found) {
8580 6 std::string warning_list;
8581
8582
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (disabled_warnings->count())
8583
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 warning_list = disabled_warnings->warnings_list();
8584 else if (enabled_warnings->count())
8585 warning_list = enabled_warnings->warnings_list();
8586
8587 6 die("Query '%s' didn't generate any of the expected warning(s) '%s'.",
8588 curr_command->query, warning_list.c_str());
8589 }
8590 1365 }
8591
8592 /// Fetch warnings generated by server while executing a query and
8593 /// append them to warnings buffer 'ds'.
8594 ///
8595 /// @param ds DYNAMIC_STRING object to store the warnings
8596 /// @param mysql mysql handle object
8597 ///
8598 /// @retval Number of warnings appended to ds
8599 3306925 static int append_warnings(DYNAMIC_STRING *ds, MYSQL *mysql) {
8600 unsigned int count;
8601
3/4
✓ Branch 0 taken 3306925 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3237529 times.
✓ Branch 3 taken 69396 times.
3306925 if (!(count = mysql_warning_count(mysql))) return 0;
8602
8603 // If one day we will support execution of multi-statements
8604 // through PS API we should not issue SHOW WARNINGS until
8605 // we have not read all results.
8606
2/4
✓ Branch 0 taken 69396 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 69396 times.
69396 assert(!mysql_more_results(mysql));
8607
8608 MYSQL_RES *warn_res;
8609
2/4
✓ Branch 0 taken 69396 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 69396 times.
69396 if (mysql_real_query_wrapper(mysql, "SHOW WARNINGS", 13))
8610 die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql));
8611
8612
2/4
✓ Branch 0 taken 69396 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 69396 times.
69396 if (!(warn_res = mysql_store_result_wrapper(mysql)))
8613 die("Warning count is %u but didn't get any warnings", count);
8614
8615 DYNAMIC_STRING ds_warnings;
8616
1/2
✓ Branch 0 taken 69396 times.
✗ Branch 1 not taken.
69396 init_dynamic_string(&ds_warnings, "", 1024);
8617
1/2
✓ Branch 0 taken 69396 times.
✗ Branch 1 not taken.
69396 append_result(&ds_warnings, warn_res);
8618
1/2
✓ Branch 0 taken 69396 times.
✗ Branch 1 not taken.
69396 mysql_free_result_wrapper(warn_res);
8619
8620
6/6
✓ Branch 0 taken 1371 times.
✓ Branch 1 taken 68025 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 1329 times.
✓ Branch 4 taken 1371 times.
✓ Branch 5 taken 68025 times.
70809 if (disable_warnings &&
8621
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
1413 (disabled_warnings->count() || enabled_warnings->count()))
8622
1/2
✓ Branch 0 taken 1365 times.
✗ Branch 1 not taken.
1371 handle_warnings(ds, ds_warnings.str);
8623
1/2
✓ Branch 0 taken 68025 times.
✗ Branch 1 not taken.
68025 else if (!disable_warnings)
8624
1/2
✓ Branch 0 taken 68025 times.
✗ Branch 1 not taken.
68025 dynstr_append_mem(ds, ds_warnings.str, ds_warnings.length);
8625
8626
1/2
✓ Branch 0 taken 69390 times.
✗ Branch 1 not taken.
69390 dynstr_free(&ds_warnings);
8627 69390 return ds->length;
8628 }
8629
8630 /// Run query using MySQL C API
8631 ///
8632 /// @param cn Connection object
8633 /// @param command Pointer to the st_command structure which holds the
8634 /// arguments and information for the command.
8635 /// @param flags Flags indicating if we should SEND and/or REAP.
8636 /// @param query Query string
8637 /// @param query_len Length of the query string
8638 /// @param ds Output buffer to store the query result.
8639 /// @param ds_warnings Buffer to store the warnings generated while
8640 /// executing the query.
8641 4233077 static void run_query_normal(struct st_connection *cn,
8642 struct st_command *command, int flags,
8643 const char *query, size_t query_len,
8644 DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) {
8645 4233077 int error = 0;
8646 4233077 std::uint32_t counter = 0;
8647 4233077 MYSQL *mysql = &cn->mysql;
8648 4233077 MYSQL_RES *res = nullptr;
8649
8650
2/2
✓ Branch 0 taken 4119135 times.
✓ Branch 1 taken 113942 times.
4233077 if (flags & QUERY_SEND_FLAG) {
8651 /* Send the query */
8652
2/2
✓ Branch 0 taken 309536 times.
✓ Branch 1 taken 3809599 times.
4119135 if (mysql_send_query_wrapper(&cn->mysql, query,
8653 static_cast<ulong>(query_len))) {
8654 309536 handle_error(command, mysql_errno(mysql), mysql_error(mysql),
8655 mysql_sqlstate(mysql), ds);
8656 309536 goto end;
8657 }
8658 }
8659
8660
2/2
✓ Branch 0 taken 116287 times.
✓ Branch 1 taken 3807254 times.
3923541 if (!(flags & QUERY_REAP_FLAG)) {
8661 116287 cn->pending = true;
8662 116287 return;
8663 }
8664
8665 do {
8666 /*
8667 When on first result set, call mysql_read_query_result_wrapper to
8668 retrieve answer to the query sent earlier
8669 */
8670
6/6
✓ Branch 0 taken 3807254 times.
✓ Branch 1 taken 760506 times.
✓ Branch 2 taken 79248 times.
✓ Branch 3 taken 3728006 times.
✓ Branch 4 taken 79248 times.
✓ Branch 5 taken 4488512 times.
4567760 if ((counter == 0) && mysql_read_query_result_wrapper(&cn->mysql)) {
8671 /* we've failed to collect the result set */
8672 79248 cn->pending = true;
8673 79248 handle_error(command, mysql_errno(mysql), mysql_error(mysql),
8674 mysql_sqlstate(mysql), ds);
8675 79214 goto end;
8676 }
8677
8678 /*
8679 Store the result of the query if it will return any fields
8680 */
8681
4/4
✓ Branch 0 taken 1155169 times.
✓ Branch 1 taken 3333343 times.
✓ Branch 2 taken 3908 times.
✓ Branch 3 taken 4484604 times.
5643681 if (mysql_field_count(mysql) &&
8682
2/2
✓ Branch 0 taken 3908 times.
✓ Branch 1 taken 1151261 times.
1155169 ((res = mysql_store_result_wrapper(mysql)) == nullptr)) {
8683 3908 handle_error(command, mysql_errno(mysql), mysql_error(mysql),
8684 mysql_sqlstate(mysql), ds);
8685 3908 goto end;
8686 }
8687
8688
2/2
✓ Branch 0 taken 4201107 times.
✓ Branch 1 taken 283497 times.
4484604 if (!disable_result_log) {
8689
2/2
✓ Branch 0 taken 1059753 times.
✓ Branch 1 taken 3141354 times.
4201107 if (res) {
8690 1059753 MYSQL_FIELD *fields = mysql_fetch_fields(res);
8691 1059753 std::uint32_t num_fields = mysql_num_fields(res);
8692
8693
2/2
✓ Branch 0 taken 297 times.
✓ Branch 1 taken 1059456 times.
1059753 if (display_metadata) append_metadata(ds, fields, num_fields);
8694
8695
2/2
✓ Branch 0 taken 1052452 times.
✓ Branch 1 taken 7301 times.
1059753 if (!display_result_vertically)
8696 1052452 append_table_headings(ds, fields, num_fields);
8697
8698 1059753 append_result(ds, res);
8699 }
8700
8701 // Need to call mysql_affected_rows() before the "new"
8702 // query to find the warnings.
8703
2/2
✓ Branch 0 taken 3142 times.
✓ Branch 1 taken 4197965 times.
4201107 if (!disable_info)
8704 3142 append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));
8705
8706
2/2
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 4200519 times.
4201107 if (display_session_track_info) append_session_track_info(ds, mysql);
8707
8708 // Add all warnings to the result. We can't do this if we are in
8709 // the middle of processing results from multi-statement, because
8710 // this will break protocol.
8711
4/4
✓ Branch 0 taken 137565 times.
✓ Branch 1 taken 1570 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 137505 times.
276700 if ((!disable_warnings || disabled_warnings->count() ||
8712
4/4
✓ Branch 0 taken 139135 times.
✓ Branch 1 taken 4061972 times.
✓ Branch 2 taken 3306925 times.
✓ Branch 3 taken 894182 times.
8539779 enabled_warnings->count()) &&
8713
2/2
✓ Branch 0 taken 3306925 times.
✓ Branch 1 taken 756677 times.
4063602 !mysql_more_results(mysql)) {
8714
5/6
✓ Branch 0 taken 3238820 times.
✓ Branch 1 taken 68099 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3238820 times.
✓ Branch 4 taken 68099 times.
✓ Branch 5 taken 3238820 times.
3306925 if (append_warnings(ds_warnings, mysql) || ds_warnings->length) {
8715 68099 dynstr_append_mem(ds, "Warnings:\n", 10);
8716 68099 dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
8717 }
8718 }
8719 }
8720
8721
2/2
✓ Branch 0 taken 1151261 times.
✓ Branch 1 taken 3333337 times.
4484598 if (res) {
8722 1151261 mysql_free_result_wrapper(res);
8723 1151261 res = nullptr;
8724 }
8725 4484598 counter++;
8726
2/2
✓ Branch 0 taken 760506 times.
✓ Branch 1 taken 3724092 times.
4484598 } while (!(error = mysql_next_result_wrapper(mysql)));
8727
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 3723933 times.
3724092 if (error > 0) {
8728 // We got an error from mysql_next_result, maybe expected.
8729 159 handle_error(command, mysql_errno(mysql), mysql_error(mysql),
8730 mysql_sqlstate(mysql), ds);
8731 153 goto end;
8732 }
8733
8734 // Successful and there are no more results.
8735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3723933 times.
3723933 assert(error == -1);
8736
8737 // If we come here the query is both executed and read successfully.
8738 3723933 handle_no_error(command);
8739 3723930 revert_properties();
8740
8741 4116741 end:
8742 4116741 cn->pending = false;
8743
8744 // We save the return code (mysql_errno(mysql)) from the last call sent
8745 // to the server into the mysqltest builtin variable $mysql_errno. This
8746 // variable then can be used from the test case itself.
8747 4116741 var_set_errno(mysql_errno(mysql));
8748 }
8749
8750 /// Run query using prepared statement C API
8751 ///
8752 /// @param mysql mysql handle
8753 /// @param command Pointer to the st_command structure which holds the
8754 /// arguments and information for the command.
8755 /// @param query Query string
8756 /// @param query_len Length of the query string
8757 /// @param ds Output buffer to store the query result.
8758 /// @param ds_warnings Buffer to store the warnings generated while
8759 /// executing the query.
8760 static void run_query_stmt(MYSQL *mysql, struct st_command *command,
8761 const char *query, size_t query_len,
8762 DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) {
8763 // Init a new stmt if it's not already one created for this connection.
8764 MYSQL_STMT *stmt;
8765 if (!(stmt = cur_con->stmt)) {
8766 if (!(stmt = mysql_stmt_init(mysql))) die("unable to init stmt structure");
8767 cur_con->stmt = stmt;
8768 }
8769
8770 DYNAMIC_STRING ds_prepare_warnings;
8771 DYNAMIC_STRING ds_execute_warnings;
8772
8773 // Init dynamic strings for warnings.
8774 if (!disable_warnings || disabled_warnings->count() ||
8775 enabled_warnings->count()) {
8776 init_dynamic_string(&ds_prepare_warnings, nullptr, 0);
8777 init_dynamic_string(&ds_execute_warnings, nullptr, 0);
8778 }
8779
8780 // Note that here 'res' is meta data result set
8781 MYSQL_RES *res = nullptr;
8782 int err = 0;
8783
8784 // Prepare the query
8785 if (mysql_stmt_prepare(stmt, query, static_cast<ulong>(query_len))) {
8786 handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt),
8787 mysql_stmt_sqlstate(stmt), ds);
8788 goto end;
8789 }
8790
8791 // Get the warnings from mysql_stmt_prepare and keep them in a
8792 // separate string.
8793 if (!disable_warnings || disabled_warnings->count() ||
8794 enabled_warnings->count())
8795 append_warnings(&ds_prepare_warnings, mysql);
8796
8797 // No need to call mysql_stmt_bind_param() because we have no
8798 // parameter markers.
8799 if (cursor_protocol_enabled) {
8800 // Use cursor when retrieving result.
8801 unsigned long type = CURSOR_TYPE_READ_ONLY;
8802 if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&type))
8803 die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s",
8804 mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
8805 }
8806
8807 // Execute the query
8808 if (mysql_stmt_execute(stmt)) {
8809 handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt),
8810 mysql_stmt_sqlstate(stmt), ds);
8811 goto end;
8812 }
8813
8814 // When running in cursor_protocol get the warnings from execute here
8815 // and keep them in a separate string for later.
8816 if (cursor_protocol_enabled &&
8817 (!disable_warnings || disabled_warnings->count() ||
8818 enabled_warnings->count()))
8819 append_warnings(&ds_execute_warnings, mysql);
8820
8821 // We instruct that we want to update the "max_length" field in
8822 // mysql_stmt_store_result(), this is our only way to know how much
8823 // buffer to allocate for result data
8824 {
8825 bool one = true;
8826 if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void *)&one))
8827 die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s",
8828 mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
8829 }
8830
8831 do {
8832 // If we got here the statement succeeded and was expected to do so,
8833 // get data. Note that this can still give errors found during execution.
8834 // Store the result of the query if if will return any fields
8835 if (mysql_stmt_field_count(stmt) && mysql_stmt_store_result(stmt)) {
8836 handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt),
8837 mysql_stmt_sqlstate(stmt), ds);
8838 goto end;
8839 }
8840
8841 if (!disable_result_log) {
8842 // Not all statements creates a result set. If there is one we can
8843 // now create another normal result set that contains the meta
8844 // data. This set can be handled almost like any other non prepared
8845 // statement result set.
8846 if ((res = mysql_stmt_result_metadata(stmt)) != nullptr) {
8847 // Take the column count from meta info
8848 MYSQL_FIELD *fields = mysql_fetch_fields(res);
8849 std::uint32_t num_fields = mysql_num_fields(res);
8850
8851 if (display_metadata) append_metadata(ds, fields, num_fields);
8852
8853 if (!display_result_vertically)
8854 append_table_headings(ds, fields, num_fields);
8855
8856 append_stmt_result(ds, stmt, fields, num_fields);
8857
8858 // Free normal result set with meta data
8859 mysql_free_result_wrapper(res);
8860 } else {
8861 // This is a query without resultset
8862 }
8863
8864 // Fetch info before fetching warnings, since it will be reset
8865 // otherwise.
8866 if (!disable_info)
8867 append_info(ds, mysql_affected_rows(stmt->mysql), mysql_info(mysql));
8868
8869 if (display_session_track_info) append_session_track_info(ds, mysql);
8870
8871 // Add all warnings to the result. We can't do this if we are in
8872 // the middle of processing results from multi-statement, because
8873 // this will break protocol.
8874 if ((!disable_warnings || disabled_warnings->count() ||
8875 enabled_warnings->count()) &&
8876 !mysql_more_results(stmt->mysql)) {
8877 // Get the warnings from execute. Append warnings to ds,
8878 // if there are any.
8879 append_warnings(&ds_execute_warnings, mysql);
8880 if (ds_execute_warnings.length || ds_prepare_warnings.length ||
8881 ds_warnings->length) {
8882 dynstr_append_mem(ds, "Warnings:\n", 10);
8883
8884 // Append warnings if exist any
8885 if (ds_warnings->length)
8886 dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
8887
8888 // Append prepare warnings if exist any
8889 if (ds_prepare_warnings.length)
8890 dynstr_append_mem(ds, ds_prepare_warnings.str,
8891 ds_prepare_warnings.length);
8892
8893 // Append execute warnings if exist any
8894 if (ds_execute_warnings.length)
8895 dynstr_append_mem(ds, ds_execute_warnings.str,
8896 ds_execute_warnings.length);
8897 }
8898 }
8899 }
8900 } while ((err = mysql_stmt_next_result(stmt)) == 0);
8901
8902 if (err > 0) {
8903 // We got an error from mysql_stmt_next_result, maybe expected.
8904 handle_error(command, mysql_stmt_errno(stmt), mysql_stmt_error(stmt),
8905 mysql_stmt_sqlstate(stmt), ds);
8906 goto end;
8907 }
8908
8909 // If we got here the statement was both executed and read successfully.
8910 handle_no_error(command);
8911
8912 end:
8913 if (!disable_warnings || disabled_warnings->count() ||
8914 enabled_warnings->count()) {
8915 dynstr_free(&ds_prepare_warnings);
8916 dynstr_free(&ds_execute_warnings);
8917 }
8918 revert_properties();
8919
8920 // We save the return code (mysql_stmt_errno(stmt)) from the last call sent
8921 // to the server into the mysqltest builtin variable $mysql_errno. This
8922 // variable then can be used from the test case itself.
8923 var_set_errno(mysql_stmt_errno(stmt));
8924
8925 // Close the statement if no reconnect, need new prepare.
8926 if (mysql->reconnect) {
8927 mysql_stmt_close(stmt);
8928 cur_con->stmt = nullptr;
8929 }
8930 }
8931
8932 /*
8933 Create a util connection if one does not already exists
8934 and use that to run the query
8935 This is done to avoid implicit commit when creating/dropping objects such
8936 as view, sp etc.
8937 */
8938
8939 static int util_query(MYSQL *org_mysql, const char *query) {
8940 MYSQL *mysql;
8941 DBUG_TRACE;
8942
8943 if (!(mysql = cur_con->util_mysql)) {
8944 DBUG_PRINT("info", ("Creating util_mysql"));
8945 if (!(mysql = mysql_init(mysql))) die("Failed in mysql_init()");
8946
8947 if (opt_init_command)
8948 mysql_options(mysql, MYSQL_INIT_COMMAND, opt_init_command);
8949 if (opt_connect_timeout)
8950 mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT,
8951 (void *)&opt_connect_timeout);
8952
8953 /* enable local infile, in non-binary builds often disabled by default */
8954 mysql_options(mysql, MYSQL_OPT_LOCAL_INFILE, nullptr);
8955 safe_connect(mysql, "util", org_mysql->host, org_mysql->user,
8956 org_mysql->passwd, org_mysql->db, org_mysql->port,
8957 org_mysql->unix_socket);
8958
8959 cur_con->util_mysql = mysql;
8960 }
8961
8962 return mysql_query_wrapper(mysql, query);
8963 }
8964
8965 /*
8966 Run query
8967
8968 SYNPOSIS
8969 run_query()
8970 mysql mysql handle
8971 command current command pointer
8972
8973 flags control the phased/stages of query execution to be performed
8974 if QUERY_SEND_FLAG bit is on, the query will be sent. If QUERY_REAP_FLAG
8975 is on the result will be read - for regular query, both bits must be on
8976 */
8977
8978 4233104 static void run_query(struct st_connection *cn, struct st_command *command,
8979 int flags) {
8980 4233104 MYSQL *mysql = &cn->mysql;
8981 DYNAMIC_STRING *ds;
8982 4233104 DYNAMIC_STRING *save_ds = nullptr;
8983 DYNAMIC_STRING ds_sorted;
8984 DYNAMIC_STRING ds_warnings;
8985 DYNAMIC_STRING eval_query;
8986 const char *query;
8987 size_t query_len;
8988 4233104 bool view_created = false, sp_created = false;
8989 4233104 bool complete_query =
8990
4/4
✓ Branch 0 taken 4119162 times.
✓ Branch 1 taken 113942 times.
✓ Branch 2 taken 4002875 times.
✓ Branch 3 taken 116287 times.
4233104 ((flags & QUERY_SEND_FLAG) && (flags & QUERY_REAP_FLAG));
8991
1/2
✓ Branch 0 taken 4233104 times.
✗ Branch 1 not taken.
4233104 DBUG_TRACE;
8992
1/2
✓ Branch 0 taken 4233104 times.
✗ Branch 1 not taken.
4233104 dynstr_set(&ds_result, "");
8993
8994
4/4
✓ Branch 0 taken 113945 times.
✓ Branch 1 taken 4119159 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 113942 times.
4233104 if (cn->pending && (flags & QUERY_SEND_FLAG))
8995 3 die("Cannot run query on connection between send and reap");
8996
8997
3/4
✓ Branch 0 taken 113942 times.
✓ Branch 1 taken 4119159 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 113942 times.
4233101 if (!(flags & QUERY_SEND_FLAG) && !cn->pending)
8998 die("Cannot reap on a connection without pending send");
8999
9000 /*
9001 Evaluate query if this is an eval command
9002 */
9003
4/4
✓ Branch 0 taken 2477181 times.
✓ Branch 1 taken 1755920 times.
✓ Branch 2 taken 10109 times.
✓ Branch 3 taken 2467072 times.
4233101 if (command->type == Q_EVAL || command->type == Q_SEND_EVAL) {
9004
1/2
✓ Branch 0 taken 1766029 times.
✗ Branch 1 not taken.
1766029 init_dynamic_string(&eval_query, "", command->query_len + 256);
9005
1/2
✓ Branch 0 taken 1766029 times.
✗ Branch 1 not taken.
1766029 do_eval(&eval_query, command->query, command->end, false);
9006 1766029 query = eval_query.str;
9007 1766029 query_len = eval_query.length;
9008 } else {
9009 2467072 query = command->query;
9010 2467072 query_len = std::strlen(query);
9011 }
9012
9013 /*
9014 Create a temporary dynamic string to contain the
9015 output from this query.
9016 */
9017
2/2
✓ Branch 0 taken 191 times.
✓ Branch 1 taken 4232910 times.
4233101 if (command->output_file[0])
9018 191 ds = &ds_result;
9019 else
9020 4232910 ds = &ds_res;
9021
9022 /*
9023 Log the query into the output buffer
9024 */
9025
4/4
✓ Branch 0 taken 1159682 times.
✓ Branch 1 taken 3073419 times.
✓ Branch 2 taken 1154029 times.
✓ Branch 3 taken 5653 times.
4233101 if (!disable_query_log && (flags & QUERY_SEND_FLAG)) {
9026
1/2
✓ Branch 0 taken 1154005 times.
✗ Branch 1 not taken.
1154029 replace_dynstr_append_mem(ds, query, query_len);
9027
1/2
✓ Branch 0 taken 1154005 times.
✗ Branch 1 not taken.
1154005 dynstr_append_mem(ds, delimiter, delimiter_length);
9028
1/2
✓ Branch 0 taken 1154005 times.
✗ Branch 1 not taken.
1154005 dynstr_append_mem(ds, "\n", 1);
9029 }
9030
9031
3/4
✓ Branch 0 taken 3564 times.
✓ Branch 1 taken 4229513 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3564 times.
4233077 if (skip_if_hypergraph && opt_hypergraph) {
9032 constexpr char message[] =
9033 "<ignored hypergraph optimizer error: statement skipped by "
9034 "test>\n";
9035 dynstr_append_mem(&ds_res, message, strlen(message));
9036 if (command->type == Q_EVAL || command->type == Q_SEND_EVAL)
9037 dynstr_free(&eval_query);
9038 return;
9039 }
9040
9041
1/2
✓ Branch 0 taken 4233077 times.
✗ Branch 1 not taken.
4233077 init_dynamic_string(&ds_warnings, nullptr, 0);
9042 4233077 ds_warn = &ds_warnings;
9043
9044
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4233077 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4233077 times.
4233077 if (view_protocol_enabled && complete_query &&
9045 search_protocol_re(&view_re, query)) {
9046 /*
9047 Create the query as a view.
9048 Use replace since view can exist from a failed mysqltest run
9049 */
9050 DYNAMIC_STRING query_str;
9051 init_dynamic_string(&query_str,
9052 "CREATE OR REPLACE VIEW mysqltest_tmp_v AS ",
9053 query_len + 64);
9054 dynstr_append_mem(&query_str, query, query_len);
9055 if (util_query(mysql, query_str.str)) {
9056 /*
9057 Failed to create the view, this is not fatal
9058 just run the query the normal way
9059 */
9060 DBUG_PRINT("view_create_error",
9061 ("Failed to create view '%s': %d: %s", query_str.str,
9062 mysql_errno(mysql), mysql_error(mysql)));
9063
9064 /* Log error to create view */
9065 verbose_msg("Failed to create view '%s' %d: %s", query_str.str,
9066 mysql_errno(mysql), mysql_error(mysql));
9067 } else {
9068 /*
9069 Yes, it was possible to create this query as a view
9070 */
9071 view_created = true;
9072 query = "SELECT * FROM mysqltest_tmp_v";
9073 query_len = std::strlen(query);
9074
9075 /*
9076 Collect warnings from create of the view that should otherwise
9077 have been produced when the SELECT was executed
9078 */
9079 append_warnings(&ds_warnings, cur_con->util_mysql);
9080 }
9081
9082 dynstr_free(&query_str);
9083 }
9084
9085
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4233077 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4233077 times.
4233077 if (sp_protocol_enabled && complete_query &&
9086 search_protocol_re(&sp_re, query)) {
9087 /*
9088 Create the query as a stored procedure
9089 Drop first since sp can exist from a failed mysqltest run
9090 */
9091 DYNAMIC_STRING query_str;
9092 init_dynamic_string(&query_str,
9093 "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;",
9094 query_len + 64);
9095 util_query(mysql, query_str.str);
9096 dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n");
9097 dynstr_append_mem(&query_str, query, query_len);
9098 if (util_query(mysql, query_str.str)) {
9099 /*
9100 Failed to create the stored procedure for this query,
9101 this is not fatal just run the query the normal way
9102 */
9103 DBUG_PRINT("sp_create_error",
9104 ("Failed to create sp '%s': %d: %s", query_str.str,
9105 mysql_errno(mysql), mysql_error(mysql)));
9106
9107 /* Log error to create sp */
9108 verbose_msg("Failed to create sp '%s' %d: %s", query_str.str,
9109 mysql_errno(mysql), mysql_error(mysql));
9110
9111 } else {
9112 sp_created = true;
9113
9114 query = "CALL mysqltest_tmp_sp()";
9115 query_len = std::strlen(query);
9116 }
9117 dynstr_free(&query_str);
9118 }
9119
9120
2/2
✓ Branch 0 taken 28584 times.
✓ Branch 1 taken 4204493 times.
4233077 if (display_result_sorted) {
9121 /*
9122 Collect the query output in a separate string
9123 that can be sorted before it's added to the
9124 global result string
9125 */
9126
1/2
✓ Branch 0 taken 28584 times.
✗ Branch 1 not taken.
28584 init_dynamic_string(&ds_sorted, "", 1024);
9127 28584 save_ds = ds; /* Remember original ds */
9128 28584 ds = &ds_sorted;
9129 }
9130
9131 /*
9132 Find out how to run this query
9133
9134 Always run with normal C API if it's not a complete
9135 SEND + REAP
9136
9137 If it is a '?' in the query it may be a SQL level prepared
9138 statement already and we can't do it twice
9139 */
9140
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4233077 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4233077 times.
4233077 if (ps_protocol_enabled && complete_query &&
9141 search_protocol_re(&ps_re, query))
9142 run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings);
9143 else
9144
1/2
✓ Branch 0 taken 4233028 times.
✗ Branch 1 not taken.
4233077 run_query_normal(cn, command, flags, query, query_len, ds, &ds_warnings);
9145
9146
1/2
✓ Branch 0 taken 4233028 times.
✗ Branch 1 not taken.
4233028 dynstr_free(&ds_warnings);
9147 4233028 ds_warn = nullptr;
9148
4/4
✓ Branch 0 taken 2477108 times.
✓ Branch 1 taken 1755920 times.
✓ Branch 2 taken 10109 times.
✓ Branch 3 taken 2466999 times.
4233028 if (command->type == Q_EVAL || command->type == Q_SEND_EVAL)
9149
1/2
✓ Branch 0 taken 1766029 times.
✗ Branch 1 not taken.
1766029 dynstr_free(&eval_query);
9150
9151
2/2
✓ Branch 0 taken 28584 times.
✓ Branch 1 taken 4204444 times.
4233028 if (display_result_sorted) {
9152 /* Sort the result set and append it to result */
9153
1/2
✓ Branch 0 taken 28584 times.
✗ Branch 1 not taken.
28584 dynstr_append_sorted(save_ds, &ds_sorted, start_sort_column);
9154 28584 ds = save_ds;
9155
1/2
✓ Branch 0 taken 28584 times.
✗ Branch 1 not taken.
28584 dynstr_free(&ds_sorted);
9156 }
9157
9158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4233028 times.
4233028 if (sp_created) {
9159 if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp "))
9160 die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql));
9161 }
9162
9163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4233028 times.
4233028 if (view_created) {
9164 if (util_query(mysql, "DROP VIEW mysqltest_tmp_v "))
9165 die("Failed to drop view: %d: %s", mysql_errno(mysql),
9166 mysql_error(mysql));
9167 }
9168
2/2
✓ Branch 0 taken 191 times.
✓ Branch 1 taken 4232837 times.
4233028 if (command->output_file[0]) {
9169 /* An output file was specified for _this_ query */
9170
1/2
✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
191 str_to_file2(command->output_file, ds_result.str, ds_result.length, false);
9171 191 command->output_file[0] = 0;
9172 }
9173
1/2
✓ Branch 0 taken 4233028 times.
✗ Branch 1 not taken.
4233028 }
9174
9175 /**
9176 Display the optimizer trace produced by the last executed statement.
9177 */
9178 4210542 static void display_opt_trace(struct st_connection *cn,
9179 struct st_command *command, int flags) {
9180
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1159449 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1159449 if (!disable_query_log && opt_trace_protocol_enabled && !cn->pending &&
9181
3/4
✓ Branch 0 taken 1159449 times.
✓ Branch 1 taken 3051093 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4210542 times.
5369991 !expected_errors->count() &&
9182 search_protocol_re(&opt_trace_re, command->query)) {
9183 st_command save_command = *command;
9184 DYNAMIC_STRING query_str;
9185 init_dynamic_string(&query_str,
9186 "SELECT trace FROM information_schema.optimizer_trace"
9187 " /* injected by --opt-trace-protocol */",
9188 128);
9189
9190 command->query = query_str.str;
9191 command->query_len = query_str.length;
9192 command->end = strend(command->query);
9193
9194 /* Sorted trace is not readable at all, don't bother to lower case */
9195 /* No need to keep old values, will be reset anyway */
9196 display_result_sorted = false;
9197 display_result_lower = false;
9198 run_query(cn, command, flags);
9199
9200 dynstr_free(&query_str);
9201 *command = save_command;
9202 }
9203 4210542 }
9204
9205 static void run_explain(struct st_connection *cn, struct st_command *command,
9206 int flags, bool json) {
9207 if ((flags & QUERY_REAP_FLAG) && !expected_errors->count() &&
9208 search_protocol_re(&explain_re, command->query)) {
9209 st_command save_command = *command;
9210 DYNAMIC_STRING query_str;
9211 DYNAMIC_STRING ds_warning_messages;
9212
9213 init_dynamic_string(&ds_warning_messages, "", 0);
9214 init_dynamic_string(&query_str, json ? "EXPLAIN FORMAT=JSON " : "EXPLAIN ",
9215 256);
9216 dynstr_append_mem(&query_str, command->query,
9217 command->end - command->query);
9218
9219 command->query = query_str.str;
9220 command->query_len = query_str.length;
9221 command->end = strend(command->query);
9222
9223 run_query(cn, command, flags);
9224
9225 dynstr_free(&query_str);
9226 dynstr_free(&ds_warning_messages);
9227
9228 *command = save_command;
9229 }
9230 }
9231
9232 192928495 static void get_command_type(struct st_command *command) {
9233 char save;
9234 uint type;
9235
1/2
✓ Branch 0 taken 192928495 times.
✗ Branch 1 not taken.
192928495 DBUG_TRACE;
9236
9237
2/2
✓ Branch 0 taken 39716901 times.
✓ Branch 1 taken 153211594 times.
192928495 if (*command->query == '}') {
9238 39716901 command->type = Q_END_BLOCK;
9239 39716901 return;
9240 }
9241
9242 153211594 save = command->query[command->first_word_len];
9243 153211594 command->query[command->first_word_len] = 0;
9244
1/2
✓ Branch 0 taken 153211594 times.
✗ Branch 1 not taken.
153211594 type = find_type(command->query, &command_typelib, FIND_TYPE_NO_PREFIX);
9245 153211594 command->query[command->first_word_len] = save;
9246
2/2
✓ Branch 0 taken 149061685 times.
✓ Branch 1 taken 4149909 times.
153211594 if (type > 0) {
9247 149061685 command->type = (enum enum_commands)type; /* Found command */
9248
9249 /*
9250 Look for case where "query" was explicitly specified to
9251 force command being sent to server
9252 */
9253
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 149061667 times.
149061685 if (type == Q_QUERY) {
9254 /* Skip the "query" part */
9255 18 command->query = command->first_argument;
9256 }
9257 } else {
9258 /* No mysqltest command matched */
9259
9260
2/2
✓ Branch 0 taken 4149906 times.
✓ Branch 1 taken 3 times.
4149909 if (command->type != Q_COMMENT_WITH_COMMAND) {
9261 /* A query that will sent to mysqld */
9262 4149906 command->type = Q_QUERY;
9263 } else {
9264 /* -- "comment" that didn't contain a mysqltest command */
9265 3 die("Found line '%s' beginning with -- that didn't contain "
9266 "a valid mysqltest command, check your syntax or "
9267 "use # if you intended to write a comment",
9268 command->query);
9269 }
9270 }
9271
2/2
✓ Branch 0 taken 153211591 times.
✓ Branch 1 taken 39716901 times.
192928492 }
9272
9273 /// Record how many milliseconds it took to execute the test file
9274 /// up until the current line and write it to .progress file.
9275 ///
9276 /// @param progress_file Logfile object to store the progress information
9277 /// @param line Line number of the progress file where the progress
9278 /// information should be recorded.
9279 static void mark_progress(Logfile *progress_file, int line) {
9280 static unsigned long long int progress_start = 0;
9281 unsigned long long int timer = timer_now();
9282
9283 if (!progress_start) progress_start = timer;
9284 timer = timer - progress_start;
9285
9286 std::string str_progress;
9287
9288 // Milliseconds since start
9289 std::string str_timer = std::to_string(timer);
9290 str_progress.append(str_timer);
9291 str_progress.append("\t");
9292
9293 // Parse the line number
9294 std::string str_line = std::to_string(line);
9295 str_progress.append(str_line);
9296 str_progress.append("\t");
9297
9298 // Filename
9299 str_progress.append(cur_file->file_name);
9300 str_progress.append(":");
9301
9302 // Line in file
9303 str_line = std::to_string(cur_file->lineno);
9304 str_progress.append(str_line);
9305 str_progress.append("\n");
9306
9307 if (progress_file->write(str_progress.c_str(), str_progress.length()) ||
9308 progress_file->flush()) {
9309 cleanup_and_exit(1);
9310 }
9311 }
9312
9313 #ifdef HAVE_STACKTRACE
9314 static void dump_backtrace() {
9315 struct st_connection *conn = cur_con;
9316
9317 fprintf(stderr, "mysqltest: ");
9318
9319 // Print the query and the line number
9320 if (start_lineno > 0) fprintf(stderr, "At line %u: ", start_lineno);
9321 fprintf(stderr, "%s\n", curr_command->query);
9322
9323 // Print the file stack
9324 if (cur_file && cur_file != file_stack) {
9325 fprintf(stderr, "In included ");
9326 print_file_stack();
9327 }
9328
9329 if (conn) fprintf(stderr, "conn->name: %s\n", conn->name);
9330
9331 fprintf(stderr, "Attempting backtrace.\n");
9332 fflush(stderr);
9333 my_print_stacktrace(nullptr, my_thread_stack_size);
9334 }
9335
9336 #else
9337 static void dump_backtrace() { fputs("Backtrace not available.\n", stderr); }
9338
9339 #endif
9340
9341 static void signal_handler(int sig) {
9342 fprintf(stderr, "mysqltest got " SIGNAL_FMT "\n", sig);
9343 dump_backtrace();
9344
9345 fprintf(stderr, "Writing a core file.\n");
9346 fflush(stderr);
9347 my_write_core(sig);
9348 #ifndef _WIN32
9349 // Shouldn't get here but just in case
9350 exit(1);
9351 #endif
9352 }
9353
9354 #ifdef _WIN32
9355
9356 LONG WINAPI exception_filter(EXCEPTION_POINTERS *exp) {
9357 __try {
9358 my_set_exception_pointers(exp);
9359 signal_handler(exp->ExceptionRecord->ExceptionCode);
9360 } __except (EXCEPTION_EXECUTE_HANDLER) {
9361 fputs("Got exception in exception handler!\n", stderr);
9362 }
9363
9364 return EXCEPTION_CONTINUE_SEARCH;
9365 }
9366
9367 static void init_signal_handling(void) {
9368 UINT mode;
9369
9370 mysqltest_thread = OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
9371 if (mysqltest_thread == NULL)
9372 die("OpenThread failed, err = %d.", GetLastError());
9373
9374 /* Set output destination of messages to the standard error stream. */
9375 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
9376 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
9377 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
9378 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
9379 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
9380 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
9381
9382 /* Do not not display the a error message box. */
9383 mode = SetErrorMode(0) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX;
9384 SetErrorMode(mode);
9385
9386 SetUnhandledExceptionFilter(exception_filter);
9387 }
9388
9389 /// Function to handle the stacktrace request event.
9390 ///
9391 /// - Suspend the thread running the test
9392 /// - Fetch CONTEXT record from the thread handle
9393 /// - Initialize EXCEPTION_RECORD structure
9394 /// - Use EXCEPTION_POINTERS and EXCEPTION_RECORD to set EXCEPTION_POINTERS
9395 /// structure
9396 /// - Call exception_filter() method to generate to stack trace
9397 /// - Resume the suspended test thread
9398 static void handle_wait_stacktrace_request_event() {
9399 fprintf(stderr, "Test case timeout failure.\n");
9400
9401 // Suspend the thread running the test
9402 if (SuspendThread(mysqltest_thread) == -1) {
9403 DWORD error = GetLastError();
9404 CloseHandle(mysqltest_thread);
9405 die("Error suspending thread, err = %d.\n", error);
9406 }
9407
9408 // Fetch the thread context
9409 CONTEXT test_thread_ctx = {0};
9410 test_thread_ctx.ContextFlags = CONTEXT_FULL;
9411
9412 if (GetThreadContext(mysqltest_thread, &test_thread_ctx) == FALSE) {
9413 DWORD error = GetLastError();
9414 CloseHandle(mysqltest_thread);
9415 die("Error while fetching thread conext information, err = %d.\n", error);
9416 }
9417
9418 EXCEPTION_POINTERS exp = {0};
9419 exp.ContextRecord = &test_thread_ctx;
9420
9421 // Set up an Exception record with EXCEPTION_BREAKPOINT code
9422 EXCEPTION_RECORD exc_rec = {0};
9423 exc_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
9424 exp.ExceptionRecord = &exc_rec;
9425
9426 exception_filter(&exp);
9427
9428 // Resume the suspended test thread
9429 if (ResumeThread(mysqltest_thread) == -1) {
9430 DWORD error = GetLastError();
9431 CloseHandle(mysqltest_thread);
9432 die("Error resuming thread, err = %d.\n", error);
9433 }
9434
9435 my_set_exception_pointers(nullptr);
9436 }
9437
9438 /// Thread waiting for timeout event to occur. If the event occurs,
9439 /// this method will trigger signal_handler() function.
9440 static void wait_stacktrace_request_event() {
9441 DWORD wait_res = WaitForSingleObject(stacktrace_request_event, INFINITE);
9442 switch (wait_res) {
9443 case WAIT_OBJECT_0:
9444 handle_wait_stacktrace_request_event();
9445 break;
9446 default:
9447 die("Unexpected result %d from WaitForSingleObject.", wait_res);
9448 break;
9449 }
9450 CloseHandle(stacktrace_request_event);
9451 }
9452
9453 /// Create an event name from the safeprocess PID value of the form
9454 /// mysqltest[%d]stacktrace and spawn thread waiting for that event
9455 /// to occur.
9456 ///
9457 /// When this event occurs, signal_handler() method is called and
9458 /// stacktrace for the mysqltest client process is printed in the
9459 /// log file.
9460 static void create_stacktrace_request_event() {
9461 char event_name[64];
9462 std::sprintf(event_name, "mysqltest[%d]stacktrace", opt_safe_process_pid);
9463
9464 // Create an event for the signal handler
9465 if ((stacktrace_request_event = CreateEvent(NULL, TRUE, FALSE, event_name)) ==
9466 NULL)
9467 die("Failed to create timeout_event.");
9468
9469 wait_for_stacktrace_request_event_thread =
9470 std::thread(wait_stacktrace_request_event);
9471 }
9472
9473 #else /* _WIN32 */
9474
9475 50135 static void init_signal_handling(void) {
9476 struct sigaction sa;
9477
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 DBUG_TRACE;
9478
9479 #ifdef HAVE_STACKTRACE
9480
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 my_init_stacktrace();
9481 #endif
9482
9483 50135 sa.sa_flags = SA_RESETHAND | SA_NODEFER;
9484 50135 sigemptyset(&sa.sa_mask);
9485 50135 sigprocmask(SIG_SETMASK, &sa.sa_mask, nullptr);
9486
9487 50135 sa.sa_handler = signal_handler;
9488
9489 50135 sigaction(SIGSEGV, &sa, nullptr);
9490 50135 sigaction(SIGABRT, &sa, nullptr);
9491 #ifdef SIGBUS
9492 50135 sigaction(SIGBUS, &sa, nullptr);
9493 #endif
9494 50135 sigaction(SIGILL, &sa, nullptr);
9495 50135 sigaction(SIGFPE, &sa, nullptr);
9496 50135 }
9497
9498 #endif /* !_WIN32 */
9499
9500 50135 int main(int argc, char **argv) {
9501 struct st_command *command;
9502 50135 bool abort_flag = false;
9503 50135 int q_send_flag = 0;
9504 50135 uint command_executed = 0, last_command_executed = 0;
9505 char output_file[FN_REFLEN];
9506
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 MY_INIT(argv[0]);
9507
9508 50135 output_file[0] = 0;
9509 50135 TMPDIR[0] = 0;
9510
9511
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 init_signal_handling();
9512
9513 /* Init file stack */
9514 50135 memset(file_stack, 0, sizeof(file_stack));
9515 50135 file_stack_end =
9516 50135 file_stack + (sizeof(file_stack) / sizeof(struct st_test_file)) - 1;
9517 50135 cur_file = file_stack;
9518
9519 /* Init block stack */
9520 50135 memset(block_stack, 0, sizeof(block_stack));
9521 50135 block_stack_end =
9522 50135 block_stack + (sizeof(block_stack) / sizeof(struct st_block)) - 1;
9523 50135 cur_block = block_stack;
9524 50135 cur_block->ok = true; /* Outer block should always be executed */
9525 50135 cur_block->cmd = cmd_none;
9526
9527
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 q_lines = new Q_lines(PSI_NOT_INSTRUMENTED);
9528
9529 50135 var_hash =
9530 new collation_unordered_map<std::string, std::unique_ptr<VAR, var_free>>(
9531
2/4
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50135 times.
✗ Branch 3 not taken.
50135 charset_info, PSI_NOT_INSTRUMENTED);
9532
9533 {
9534 50135 char path_separator[] = {FN_LIBCHAR, 0};
9535
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 var_set_string("SYSTEM_PATH_SEPARATOR", path_separator);
9536 }
9537
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 var_set_string("MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION);
9538
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 var_set_string("MYSQL_SYSTEM_TYPE", SYSTEM_TYPE);
9539
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 var_set_string("MYSQL_MACHINE_TYPE", MACHINE_TYPE);
9540 if (sizeof(void *) == 8) {
9541
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 var_set_string("MYSQL_SYSTEM_ARCHITECTURE", "64");
9542 } else {
9543 var_set_string("MYSQL_SYSTEM_ARCHITECTURE", "32");
9544 }
9545
9546 50135 memset(&master_pos, 0, sizeof(master_pos));
9547
9548 50135 parser.current_line = parser.read_lines = 0;
9549 50135 memset(&var_reg, 0, sizeof(var_reg));
9550
9551 50135 init_builtin_echo();
9552 #ifdef _WIN32
9553 is_windows = 1;
9554 init_win_path_patterns();
9555 #endif
9556
9557
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 init_dynamic_string(&ds_res, "", 2048);
9558
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 init_dynamic_string(&ds_result, "", 1024);
9559
9560
1/2
✓ Branch 0 taken 50135 times.
✗ Branch 1 not taken.
50135 global_attrs = new client_query_attributes();
9561
9562
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50135 parse_args(argc, argv);
9563
9564 #ifdef _WIN32
9565 // Create an event to request stack trace when timeout occurs
9566 if (opt_safe_process_pid) create_stacktrace_request_event();
9567 #endif
9568
9569 /* Init connections, allocate 1 extra as buffer + 1 for default */
9570 100222 connections = (struct st_connection *)my_malloc(
9571 PSI_NOT_INSTRUMENTED,
9572
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 (opt_max_connections + 2) * sizeof(struct st_connection),
9573 MYF(MY_WME | MY_ZEROFILL));
9574 50111 connections_end = connections + opt_max_connections + 1;
9575 50111 next_con = connections + 1;
9576
9577
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$PS_PROTOCOL", ps_protocol);
9578
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$SP_PROTOCOL", sp_protocol);
9579
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$VIEW_PROTOCOL", view_protocol);
9580
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$OPT_TRACE_PROTOCOL", opt_trace_protocol);
9581
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$EXPLAIN_PROTOCOL", explain_protocol);
9582
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$JSON_EXPLAIN_PROTOCOL", json_explain_protocol);
9583
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$CURSOR_PROTOCOL", cursor_protocol);
9584
9585
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_QUERY_LOG", 1);
9586
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_ABORT_ON_ERROR", 1);
9587
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_RESULT_LOG", 1);
9588
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_CONNECT_LOG", 0);
9589
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_WARNINGS", 1);
9590
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_INFO", 0);
9591
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_METADATA", 0);
9592
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_int("$ENABLE_ASYNC_CLIENT", 0);
9593
9594
3/10
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50111 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 50111 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
50111 DBUG_PRINT("info",
9595 ("result_file: '%s'", result_file_name ? result_file_name : ""));
9596
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 verbose_msg("Results saved in '%s'.",
9597
2/2
✓ Branch 0 taken 36107 times.
✓ Branch 1 taken 14004 times.
50111 result_file_name ? result_file_name : "");
9598
2/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50111 times.
50111 if (mysql_server_init(0, nullptr, nullptr))
9599 die("Can't initialize MySQL server");
9600 50111 server_initialized = true;
9601
3/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 711 times.
✓ Branch 3 taken 49400 times.
50111 if (cur_file == file_stack && cur_file->file == nullptr) {
9602 711 cur_file->file = stdin;
9603 1422 cur_file->file_name =
9604
1/2
✓ Branch 0 taken 711 times.
✗ Branch 1 not taken.
711 my_strdup(PSI_NOT_INSTRUMENTED, "<stdin>", MYF(MY_WME));
9605 711 cur_file->lineno = 1;
9606 }
9607
9608
2/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50111 times.
50111 if (log_file.open(opt_logdir, result_file_name, ".log")) cleanup_and_exit(1);
9609
9610
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 verbose_msg("Logging to '%s'.", log_file.file_name());
9611 50111 enable_async_client = use_async_client;
9612
9613 // Creating a log file using current file name if result file doesn't exist.
9614
2/2
✓ Branch 0 taken 36107 times.
✓ Branch 1 taken 14004 times.
50111 if (result_file_name) {
9615
2/4
✓ Branch 0 taken 36107 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36107 times.
36107 if (log_file.open(opt_logdir, result_file_name, ".log"))
9616 cleanup_and_exit(1);
9617 } else {
9618
2/2
✓ Branch 0 taken 13293 times.
✓ Branch 1 taken 711 times.
14004 if (std::strcmp(cur_file->file_name, "<stdin>")) {
9619
2/4
✓ Branch 0 taken 13293 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13293 times.
13293 if (log_file.open(opt_logdir, cur_file->file_name, ".log"))
9620 cleanup_and_exit(1);
9621 } else {
9622
2/4
✓ Branch 0 taken 711 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 711 times.
711 if (log_file.open(opt_logdir, "stdin", ".log")) cleanup_and_exit(1);
9623 }
9624 }
9625
9626
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (opt_mark_progress) {
9627 if (result_file_name) {
9628 if (progress_file.open(opt_logdir, result_file_name, ".progress"))
9629 cleanup_and_exit(1);
9630 } else {
9631 if (std::strcmp(cur_file->file_name, "<stdin>")) {
9632 if (progress_file.open(opt_logdir, cur_file->file_name, ".progress"))
9633 cleanup_and_exit(1);
9634 } else {
9635 if (progress_file.open(opt_logdir, "stdin", ".progress"))
9636 cleanup_and_exit(1);
9637 }
9638 }
9639 verbose_msg("Tracing progress in '%s'.", progress_file.file_name());
9640 }
9641
9642
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 var_set_string("MYSQLTEST_FILE", cur_file->file_name);
9643
9644 /* Cursor protocol implies ps protocol */
9645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (cursor_protocol) ps_protocol = true;
9646
9647 50111 ps_protocol_enabled = ps_protocol;
9648 50111 sp_protocol_enabled = sp_protocol;
9649 50111 view_protocol_enabled = view_protocol;
9650 50111 opt_trace_protocol_enabled = opt_trace_protocol;
9651 50111 explain_protocol_enabled = explain_protocol;
9652 50111 json_explain_protocol_enabled = json_explain_protocol;
9653 50111 cursor_protocol_enabled = cursor_protocol;
9654
9655 50111 st_connection *con = connections;
9656
2/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50111 times.
50111 if (!(mysql_init(&con->mysql))) die("Failed in mysql_init()");
9657
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (opt_init_command)
9658 mysql_options(&con->mysql, MYSQL_INIT_COMMAND, opt_init_command);
9659
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 if (opt_connect_timeout)
9660
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 mysql_options(&con->mysql, MYSQL_OPT_CONNECT_TIMEOUT,
9661 (void *)&opt_connect_timeout);
9662
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 50110 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
50111 if (opt_compress) mysql_options(&con->mysql, MYSQL_OPT_COMPRESS, NullS);
9663
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 mysql_options(&con->mysql, MYSQL_OPT_LOCAL_INFILE, nullptr);
9664
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50111 times.
50111 if (0 != std::strcmp(default_charset, charset_info->csname) &&
9665 !(charset_info =
9666 get_charset_by_csname(default_charset, MY_CS_PRIMARY, MYF(MY_WME))))
9667 die("Invalid character set specified.");
9668
1/2
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
50111 mysql_options(&con->mysql, MYSQL_SET_CHARSET_NAME, charset_info->csname);
9669
2/2
✓ Branch 0 taken 10454 times.
✓ Branch 1 taken 39657 times.
50111 if (opt_charsets_dir)
9670
1/2
✓ Branch 0 taken 10454 times.
✗ Branch 1 not taken.
10454 mysql_options(&con->mysql, MYSQL_SET_CHARSET_DIR, opt_charsets_dir);
9671
9672
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 50109 times.
50111 if (opt_protocol)
9673
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 mysql_options(&con->mysql, MYSQL_OPT_PROTOCOL, (char *)&opt_protocol);
9674
9675 /* Turn on VERIFY_IDENTITY mode only if host=="localhost". */
9676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50111 times.
50111 if (opt_ssl_mode == SSL_MODE_VERIFY_IDENTITY) {
9677 if (!opt_host || std::strcmp(opt_host, "localhost"))
9678 opt_ssl_mode = SSL_MODE_VERIFY_CA;
9679 }
9680
9681
2/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50111 times.
50111 if (SSL_SET_OPTIONS(&con->mysql)) die("%s", SSL_SET_OPTIONS_ERROR);
9682 #if defined(_WIN32)
9683 if (shared_memory_base_name)
9684 mysql_options(&con->mysql, MYSQL_SHARED_MEMORY_BASE_NAME,
9685 shared_memory_base_name);
9686
9687 if (opt_ssl_mode == SSL_MODE_DISABLED)
9688 mysql_options(&con->mysql, MYSQL_OPT_PROTOCOL,
9689 (char *)&opt_protocol_for_default_connection);
9690 #endif
9691
9692
2/4
✓ Branch 0 taken 50111 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50111 times.
50111 if (!(con->name = my_strdup(PSI_NOT_INSTRUMENTED, "default", MYF(MY_WME))))
9693 die("Out of memory");
9694
9695
1/2
✓ Branch 0 taken 50105 times.
✗ Branch 1 not taken.
50111 safe_connect(&con->mysql, con->name, opt_host, opt_user, opt_pass, opt_db,
9696 opt_port, unix_sock);
9697
9698
2/4
✓ Branch 0 taken 50103 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 50103 times.
50105 if (ssl_client_check_post_connect_ssl_setup(
9699 2 &con->mysql, [](const char *err) { die("%s", err); }))
9700 return 0;
9701
9702 /* Use all time until exit if no explicit 'start_timer' */
9703 50103 timer_start = timer_now();
9704
9705 /*
9706 Initialize $mysql_errno with -1, so we can
9707 - distinguish it from valid values ( >= 0 ) and
9708 - detect if there was never a command sent to the server
9709 */
9710
1/2
✓ Branch 0 taken 50103 times.
✗ Branch 1 not taken.
50103 var_set_errno(-1);
9711
9712
1/2
✓ Branch 0 taken 50103 times.
✗ Branch 1 not taken.
50103 set_current_connection(con);
9713
9714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50103 times.
50103 if (opt_hypergraph) {
9715 int error = mysql_query_wrapper(
9716 &con->mysql, "SET optimizer_switch='hypergraph_optimizer=on';");
9717 if (error != 0) {
9718 die("--hypergraph was given, but the server does not support the "
9719 "hypergraph optimizer. (errno=%d)",
9720 my_errno());
9721 }
9722 }
9723
9724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50103 times.
50103 if (opt_include) {
9725 open_file(opt_include);
9726 }
9727
9728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50103 times.
50103 if (opt_offload_count_file) {
9729 secondary_engine = new Secondary_engine();
9730 // Save the initial value of secondary engine execution status.
9731 if (secondary_engine->offload_count(&cur_con->mysql, "before"))
9732 cleanup_and_exit(1);
9733 }
9734
9735
1/2
✓ Branch 0 taken 50103 times.
✗ Branch 1 not taken.
50103 verbose_msg("Start processing test commands from '%s' ...",
9736 cur_file->file_name);
9737
7/8
✓ Branch 0 taken 1824062889 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1824027088 times.
✓ Branch 3 taken 35801 times.
✓ Branch 4 taken 1824027065 times.
✓ Branch 5 taken 23 times.
✓ Branch 6 taken 1824027065 times.
✓ Branch 7 taken 35824 times.
1824062904 while (!read_command(&command) && !abort_flag) {
9738 1824027065 int current_line_inc = 1, processed = 0;
9739
4/4
✓ Branch 0 taken 1732062960 times.
✓ Branch 1 taken 91964105 times.
✓ Branch 2 taken 100964390 times.
✓ Branch 3 taken 1631098570 times.
1824027065 if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND)
9740
1/2
✓ Branch 0 taken 192928492 times.
✗ Branch 1 not taken.
192928495 get_command_type(command);
9741
9742
6/6
✓ Branch 0 taken 2423405 times.
✓ Branch 1 taken 1821603657 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 2423339 times.
✓ Branch 4 taken 66 times.
✓ Branch 5 taken 1824026996 times.
1824027062 if (command->type == Q_ERROR && expected_errors->count())
9743 // Delete all the error codes from previous 'error' command.
9744 66 expected_errors->clear_list();
9745
9746
4/4
✓ Branch 0 taken 1522 times.
✓ Branch 1 taken 1824025540 times.
✓ Branch 2 taken 1465 times.
✓ Branch 3 taken 57 times.
1824027062 if (testcase_disabled && command->type != Q_ENABLE_TESTCASE &&
9747
2/2
✓ Branch 0 taken 1462 times.
✓ Branch 1 taken 3 times.
1465 command->type != Q_DISABLE_TESTCASE) {
9748 // Test case is disabled, silently convert this line to a comment
9749 1462 command->type = Q_COMMENT;
9750 }
9751
9752 /* (Re-)set abort_on_error for this command */
9753
4/4
✓ Branch 0 taken 1823360248 times.
✓ Branch 1 taken 666814 times.
✓ Branch 2 taken 1817599524 times.
✓ Branch 3 taken 5760724 times.
1824027062 command->abort_on_error = (expected_errors->count() == 0 && abort_on_error);
9754
9755 /* delimiter needs to be executed so we can continue to parse */
9756
4/4
✓ Branch 0 taken 1650284875 times.
✓ Branch 1 taken 173742187 times.
✓ Branch 2 taken 57026 times.
✓ Branch 3 taken 1650227849 times.
1824027062 bool ok_to_do = cur_block->ok || command->type == Q_DELIMITER;
9757
9758 /*
9759 'source' command needs to be "done" the first time if it may get
9760 re-iterated over in a true context. This can only happen if there's
9761 a while loop at some level above the current block.
9762 */
9763
4/4
✓ Branch 0 taken 1650227849 times.
✓ Branch 1 taken 173799213 times.
✓ Branch 2 taken 15654615 times.
✓ Branch 3 taken 1634573234 times.
1824027062 if (!ok_to_do && command->type == Q_SOURCE) {
9764
2/2
✓ Branch 0 taken 55337940 times.
✓ Branch 1 taken 344323 times.
55682263 for (struct st_block *stb = cur_block - 1; stb >= block_stack; stb--) {
9765
2/2
✓ Branch 0 taken 15310292 times.
✓ Branch 1 taken 40027648 times.
55337940 if (stb->cmd == cmd_while) {
9766 15310292 ok_to_do = true;
9767 15310292 break;
9768 }
9769 }
9770 }
9771
9772 /*
9773 Some commands need to be parsed in false context also to
9774 avoid any parsing errors.
9775 */
9776
2/2
✓ Branch 0 taken 1634917557 times.
✓ Branch 1 taken 189109505 times.
1824027062 if (!ok_to_do &&
9777
4/4
✓ Branch 0 taken 1634908341 times.
✓ Branch 1 taken 9216 times.
✓ Branch 2 taken 1633559457 times.
✓ Branch 3 taken 1348884 times.
1634917557 (command->type == Q_APPEND_FILE || command->type == Q_PERL ||
9778
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 1633559363 times.
1633559457 command->type == Q_WRITE_FILE)) {
9779 1358194 ok_to_do = true;
9780 }
9781
9782
2/2
✓ Branch 0 taken 190467699 times.
✓ Branch 1 taken 1633559363 times.
1824027062 if (ok_to_do) {
9783 190467699 command->last_argument = command->first_argument;
9784 190467699 processed = 1;
9785 /* Need to remember this for handle_error() */
9786 190467699 curr_command = command;
9787
89/92
✓ Branch 0 taken 46267 times.
✓ Branch 1 taken 1025271 times.
✓ Branch 2 taken 31435 times.
✓ Branch 3 taken 533294 times.
✓ Branch 4 taken 512251 times.
✓ Branch 5 taken 487637 times.
✓ Branch 6 taken 12548 times.
✓ Branch 7 taken 529780 times.
✓ Branch 8 taken 79724 times.
✓ Branch 9 taken 438 times.
✓ Branch 10 taken 383 times.
✓ Branch 11 taken 31554 times.
✓ Branch 12 taken 39323 times.
✓ Branch 13 taken 2270 times.
✓ Branch 14 taken 2281 times.
✓ Branch 15 taken 22 times.
✓ Branch 16 taken 21 times.
✓ Branch 17 taken 186 times.
✓ Branch 18 taken 186 times.
✓ Branch 19 taken 17652382 times.
✓ Branch 20 taken 524906 times.
✓ Branch 21 taken 208 times.
✓ Branch 22 taken 1064172 times.
✓ Branch 23 taken 2540677 times.
✓ Branch 24 taken 1796419 times.
✓ Branch 25 taken 107911 times.
✓ Branch 26 taken 671 times.
✓ Branch 27 taken 207 times.
✓ Branch 28 taken 366 times.
✓ Branch 29 taken 240 times.
✓ Branch 30 taken 716 times.
✓ Branch 31 taken 67 times.
✓ Branch 32 taken 773 times.
✓ Branch 33 taken 304 times.
✓ Branch 34 taken 131701 times.
✓ Branch 35 taken 714 times.
✓ Branch 36 taken 27661 times.
✓ Branch 37 taken 143981 times.
✓ Branch 38 taken 9176 times.
✓ Branch 39 taken 2000 times.
✓ Branch 40 taken 109 times.
✓ Branch 41 taken 13147 times.
✓ Branch 42 taken 3721 times.
✓ Branch 43 taken 274 times.
✓ Branch 44 taken 349 times.
✓ Branch 45 taken 1389021 times.
✗ Branch 46 not taken.
✓ Branch 47 taken 109446 times.
✓ Branch 48 taken 775 times.
✓ Branch 49 taken 756 times.
✓ Branch 50 taken 28521 times.
✓ Branch 51 taken 78 times.
✓ Branch 52 taken 34 times.
✓ Branch 53 taken 3565 times.
✓ Branch 54 taken 19740166 times.
✓ Branch 55 taken 67987 times.
✓ Branch 56 taken 1760956 times.
✓ Branch 57 taken 2449662 times.
✓ Branch 58 taken 116287 times.
✓ Branch 59 taken 666431 times.
✓ Branch 60 taken 32552 times.
✓ Branch 61 taken 10426 times.
✓ Branch 62 taken 12288 times.
✓ Branch 63 taken 319 times.
✓ Branch 64 taken 232 times.
✓ Branch 65 taken 185 times.
✓ Branch 66 taken 1555 times.
✓ Branch 67 taken 100041498 times.
✓ Branch 68 taken 10242275 times.
✓ Branch 69 taken 8 times.
✓ Branch 70 taken 31 times.
✓ Branch 71 taken 10 times.
✓ Branch 72 taken 28 times.
✓ Branch 73 taken 3549 times.
✓ Branch 74 taken 23488 times.
✓ Branch 75 taken 10648 times.
✗ Branch 76 not taken.
✗ Branch 77 not taken.
✓ Branch 78 taken 271 times.
✓ Branch 79 taken 280 times.
✓ Branch 80 taken 249 times.
✓ Branch 81 taken 10728 times.
✓ Branch 82 taken 10749 times.
✓ Branch 83 taken 35 times.
✓ Branch 84 taken 35 times.
✓ Branch 85 taken 75 times.
✓ Branch 86 taken 60 times.
✓ Branch 87 taken 16 times.
✓ Branch 88 taken 54 times.
✓ Branch 89 taken 13539 times.
✓ Branch 90 taken 191 times.
✓ Branch 91 taken 26360917 times.
190467699 switch (command->type) {
9788 46267 case Q_CONNECT:
9789
1/2
✓ Branch 0 taken 46237 times.
✗ Branch 1 not taken.
46267 do_connect(command);
9790 46237 break;
9791 1025271 case Q_CONNECTION:
9792
1/2
✓ Branch 0 taken 1025268 times.
✗ Branch 1 not taken.
1025271 select_connection(command);
9793 1025268 break;
9794 31435 case Q_DISCONNECT:
9795 case Q_DIRTY_CLOSE:
9796
1/2
✓ Branch 0 taken 31429 times.
✗ Branch 1 not taken.
31435 do_close_connection(command);
9797 31429 break;
9798 533294 case Q_ENABLE_QUERY_LOG:
9799
1/2
✓ Branch 0 taken 533294 times.
✗ Branch 1 not taken.
533294 set_property(command, P_QUERY, false);
9800 533294 break;
9801 512251 case Q_DISABLE_QUERY_LOG:
9802
1/2
✓ Branch 0 taken 512251 times.
✗ Branch 1 not taken.
512251 set_property(command, P_QUERY, true);
9803 512251 break;
9804 487637 case Q_ENABLE_ABORT_ON_ERROR:
9805
1/2
✓ Branch 0 taken 487637 times.
✗ Branch 1 not taken.
487637 set_property(command, P_ABORT, true);
9806 487637 break;
9807 12548 case Q_DISABLE_ABORT_ON_ERROR:
9808
1/2
✓ Branch 0 taken 12548 times.
✗ Branch 1 not taken.
12548 set_property(command, P_ABORT, false);
9809 12548 break;
9810 529780 case Q_ENABLE_RESULT_LOG:
9811
1/2
✓ Branch 0 taken 529780 times.
✗ Branch 1 not taken.
529780 set_property(command, P_RESULT, false);
9812 529780 break;
9813 79724 case Q_DISABLE_RESULT_LOG:
9814
1/2
✓ Branch 0 taken 79724 times.
✗ Branch 1 not taken.
79724 set_property(command, P_RESULT, true);
9815 79724 break;
9816 438 case Q_ENABLE_CONNECT_LOG:
9817
1/2
✓ Branch 0 taken 438 times.
✗ Branch 1 not taken.
438 set_property(command, P_CONNECT, false);
9818 438 break;
9819 383 case Q_DISABLE_CONNECT_LOG:
9820
1/2
✓ Branch 0 taken 383 times.
✗ Branch 1 not taken.
383 set_property(command, P_CONNECT, true);
9821 383 break;
9822 31554 case Q_ENABLE_WARNINGS:
9823
1/2
✓ Branch 0 taken 31533 times.
✗ Branch 1 not taken.
31554 do_enable_warnings(command);
9824 31533 break;
9825 39323 case Q_DISABLE_WARNINGS:
9826
1/2
✓ Branch 0 taken 39305 times.
✗ Branch 1 not taken.
39323 do_disable_warnings(command);
9827 39305 break;
9828 2270 case Q_ENABLE_INFO:
9829
1/2
✓ Branch 0 taken 2270 times.
✗ Branch 1 not taken.
2270 set_property(command, P_INFO, false);
9830 2270 break;
9831 2281 case Q_DISABLE_INFO:
9832
1/2
✓ Branch 0 taken 2281 times.
✗ Branch 1 not taken.
2281 set_property(command, P_INFO, true);
9833 2281 break;
9834 22 case Q_ENABLE_SESSION_TRACK_INFO:
9835
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 set_property(command, P_SESSION_TRACK, true);
9836 22 break;
9837 21 case Q_DISABLE_SESSION_TRACK_INFO:
9838
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 set_property(command, P_SESSION_TRACK, false);
9839 21 break;
9840 186 case Q_ENABLE_METADATA:
9841
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 set_property(command, P_META, true);
9842 186 break;
9843 186 case Q_DISABLE_METADATA:
9844
1/2
✓ Branch 0 taken 186 times.
✗ Branch 1 not taken.
186 set_property(command, P_META, false);
9845 186 break;
9846 17652382 case Q_SOURCE:
9847
1/2
✓ Branch 0 taken 17652373 times.
✗ Branch 1 not taken.
17652382 do_source(command);
9848 17652373 break;
9849 524906 case Q_SLEEP:
9850
1/2
✓ Branch 0 taken 524885 times.
✗ Branch 1 not taken.
524906 do_sleep(command);
9851 524885 break;
9852 208 case Q_WAIT_FOR_SLAVE_TO_STOP:
9853
1/2
✓ Branch 0 taken 208 times.
✗ Branch 1 not taken.
208 do_wait_for_slave_to_stop(command);
9854 208 break;
9855 1064172 case Q_INC:
9856
1/2
✓ Branch 0 taken 1064157 times.
✗ Branch 1 not taken.
1064172 do_modify_var(command, DO_INC);
9857 1064157 break;
9858 2540677 case Q_DEC:
9859
1/2
✓ Branch 0 taken 2540662 times.
✗ Branch 1 not taken.
2540677 do_modify_var(command, DO_DEC);
9860 2540662 break;
9861 1796419 case Q_ECHO:
9862
1/2
✓ Branch 0 taken 1796419 times.
✗ Branch 1 not taken.
1796419 do_echo(command);
9863 1796419 command_executed++;
9864 1796419 break;
9865 107911 case Q_REMOVE_FILE:
9866
1/2
✓ Branch 0 taken 107890 times.
✗ Branch 1 not taken.
107911 do_remove_file(command);
9867 107890 break;
9868 671 case Q_REMOVE_FILES_WILDCARD:
9869
1/2
✓ Branch 0 taken 650 times.
✗ Branch 1 not taken.
671 do_remove_files_wildcard(command);
9870 650 break;
9871 207 case Q_COPY_FILES_WILDCARD:
9872
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
207 do_copy_files_wildcard(command);
9873 189 break;
9874 366 case Q_MKDIR:
9875
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 do_mkdir(command);
9876 366 break;
9877 240 case Q_RMDIR:
9878
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 do_rmdir(command, false);
9879 240 break;
9880 716 case Q_FORCE_RMDIR:
9881
1/2
✓ Branch 0 taken 716 times.
✗ Branch 1 not taken.
716 do_rmdir(command, true);
9882 716 break;
9883 67 case Q_FORCE_CPDIR:
9884
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 do_force_cpdir(command);
9885 67 break;
9886 773 case Q_LIST_FILES:
9887
1/2
✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
773 do_list_files(command);
9888 773 break;
9889 304 case Q_LIST_FILES_WRITE_FILE:
9890
1/2
✓ Branch 0 taken 304 times.
✗ Branch 1 not taken.
304 do_list_files_write_file_command(command, false);
9891 304 break;
9892 131701 case Q_LIST_FILES_APPEND_FILE:
9893
1/2
✓ Branch 0 taken 131701 times.
✗ Branch 1 not taken.
131701 do_list_files_write_file_command(command, true);
9894 131701 break;
9895 714 case Q_FILE_EXIST:
9896
1/2
✓ Branch 0 taken 696 times.
✗ Branch 1 not taken.
714 do_file_exist(command);
9897 696 break;
9898 27661 case Q_WRITE_FILE:
9899
1/2
✓ Branch 0 taken 27652 times.
✗ Branch 1 not taken.
27661 do_write_file(command);
9900 27652 break;
9901 143981 case Q_APPEND_FILE:
9902
1/2
✓ Branch 0 taken 143981 times.
✗ Branch 1 not taken.
143981 do_append_file(command);
9903 143981 break;
9904 9176 case Q_DIFF_FILES:
9905
1/2
✓ Branch 0 taken 9176 times.
✗ Branch 1 not taken.
9176 do_diff_files(command);
9906 9176 break;
9907 2000 case Q_SEND_QUIT:
9908
1/2
✓ Branch 0 taken 2000 times.
✗ Branch 1 not taken.
2000 do_send_quit(command);
9909 2000 break;
9910 109 case Q_CHANGE_USER:
9911
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 do_change_user(command);
9912 109 break;
9913 13147 case Q_CAT_FILE:
9914
1/2
✓ Branch 0 taken 13144 times.
✗ Branch 1 not taken.
13147 do_cat_file(command);
9915 13144 break;
9916 3721 case Q_COPY_FILE:
9917
1/2
✓ Branch 0 taken 3700 times.
✗ Branch 1 not taken.
3721 do_copy_file(command);
9918 3700 break;
9919 274 case Q_MOVE_FILE:
9920
1/2
✓ Branch 0 taken 253 times.
✗ Branch 1 not taken.
274 do_move_file(command);
9921 253 break;
9922 349 case Q_CHMOD_FILE:
9923
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
349 do_chmod_file(command);
9924 331 break;
9925 1389021 case Q_PERL:
9926
1/2
✓ Branch 0 taken 1389012 times.
✗ Branch 1 not taken.
1389021 do_perl(command);
9927 1389012 break;
9928 case Q_RESULT_FORMAT_VERSION:
9929 do_result_format_version(command);
9930 break;
9931 109446 case Q_DELIMITER:
9932
1/2
✓ Branch 0 taken 109446 times.
✗ Branch 1 not taken.
109446 do_delimiter(command);
9933 109446 break;
9934 775 case Q_DISPLAY_VERTICAL_RESULTS:
9935 775 display_result_vertically = true;
9936 775 break;
9937 756 case Q_DISPLAY_HORIZONTAL_RESULTS:
9938 756 display_result_vertically = false;
9939 756 break;
9940 28521 case Q_SORTED_RESULT:
9941 /*
9942 Turn on sorting of result set, will be reset after next
9943 command
9944 */
9945 28521 display_result_sorted = true;
9946 28521 start_sort_column = 0;
9947 28521 break;
9948 78 case Q_PARTIALLY_SORTED_RESULT:
9949 /*
9950 Turn on sorting of result set, will be reset after next
9951 command
9952 */
9953 78 display_result_sorted = true;
9954 78 start_sort_column = atoi(command->first_argument);
9955 78 command->last_argument = command->end;
9956 78 break;
9957 34 case Q_LOWERCASE:
9958 /*
9959 Turn on lowercasing of result, will be reset after next
9960 command
9961 */
9962 34 display_result_lower = true;
9963 34 break;
9964 3565 case Q_SKIP_IF_HYPERGRAPH:
9965 /*
9966 Skip the next query if running with --hypergraph; will be reset
9967 after next command.
9968 */
9969 3565 skip_if_hypergraph = true;
9970 3565 break;
9971 19740166 case Q_LET:
9972
1/2
✓ Branch 0 taken 19740087 times.
✗ Branch 1 not taken.
19740166 do_let(command);
9973 19740087 break;
9974 67987 case Q_EXPR:
9975
1/2
✓ Branch 0 taken 67951 times.
✗ Branch 1 not taken.
67987 do_expr(command);
9976 67951 break;
9977 1760956 case Q_EVAL:
9978 case Q_QUERY_VERTICAL:
9979 case Q_QUERY_HORIZONTAL:
9980
2/2
✓ Branch 0 taken 259119 times.
✓ Branch 1 taken 1501837 times.
1760956 if (command->query == command->query_buf) {
9981 /* Skip the first part of command, i.e query_xxx */
9982 259119 command->query = command->first_argument;
9983 259119 command->first_word_len = 0;
9984 }
9985 [[fallthrough]];
9986 case Q_QUERY:
9987 case Q_REAP: {
9988 4210618 bool old_display_result_vertically = display_result_vertically;
9989 /* Default is full query, both reap and send */
9990 4210618 int flags = QUERY_REAP_FLAG | QUERY_SEND_FLAG;
9991
9992
2/2
✓ Branch 0 taken 93801 times.
✓ Branch 1 taken 4116817 times.
4210618 if (q_send_flag) {
9993 // Last command was an empty 'send' or 'send_eval'
9994 93801 flags = QUERY_SEND_FLAG;
9995
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 93789 times.
93801 if (q_send_flag == 2)
9996 // Last command was an empty 'send_eval' command. Set the command
9997 // type to Q_SEND_EVAL so that the variable gets replaced with its
9998 // value before executing.
9999 12 command->type = Q_SEND_EVAL;
10000 93801 q_send_flag = 0;
10001
2/2
✓ Branch 0 taken 113942 times.
✓ Branch 1 taken 4002875 times.
4116817 } else if (command->type == Q_REAP) {
10002 113942 flags = QUERY_REAP_FLAG;
10003 }
10004
10005 /* Check for special property for this query */
10006 4210618 display_result_vertically |= (command->type == Q_QUERY_VERTICAL);
10007
10008 /*
10009 We run EXPLAIN _before_ the query. If query is UPDATE/DELETE is
10010 matters: a DELETE may delete rows, and then EXPLAIN DELETE will
10011 usually terminate quickly with "no matching rows". To make it more
10012 interesting, EXPLAIN is now first.
10013 */
10014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4210618 times.
4210618 if (explain_protocol_enabled)
10015 run_explain(cur_con, command, flags, false);
10016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4210618 times.
4210618 if (json_explain_protocol_enabled)
10017 run_explain(cur_con, command, flags, true);
10018
10019
2/2
✓ Branch 0 taken 191 times.
✓ Branch 1 taken 4210427 times.
4210618 if (*output_file) {
10020
1/2
✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
191 strmake(command->output_file, output_file, sizeof(output_file) - 1);
10021 191 *output_file = 0;
10022 }
10023
1/2
✓ Branch 0 taken 4210542 times.
✗ Branch 1 not taken.
4210618 run_query(cur_con, command, flags);
10024
1/2
✓ Branch 0 taken 4210542 times.
✗ Branch 1 not taken.
4210542 display_opt_trace(cur_con, command, flags);
10025 4210542 command_executed++;
10026 4210542 command->last_argument = command->end;
10027
10028 /* Restore settings */
10029 4210542 display_result_vertically = old_display_result_vertically;
10030
10031 4210542 break;
10032 }
10033 116287 case Q_SEND:
10034 case Q_SEND_EVAL:
10035
2/2
✓ Branch 0 taken 93801 times.
✓ Branch 1 taken 22486 times.
116287 if (!*command->first_argument) {
10036 // This is a 'send' or 'send_eval' command without arguments, it
10037 // indicates that _next_ query should be send only.
10038
2/2
✓ Branch 0 taken 93789 times.
✓ Branch 1 taken 12 times.
93801 if (command->type == Q_SEND)
10039 93789 q_send_flag = 1;
10040
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 else if (command->type == Q_SEND_EVAL)
10041 12 q_send_flag = 2;
10042 93801 break;
10043 }
10044
10045 /* Remove "send" if this is first iteration */
10046
2/2
✓ Branch 0 taken 3915 times.
✓ Branch 1 taken 18571 times.
22486 if (command->query == command->query_buf)
10047 3915 command->query = command->first_argument;
10048
10049 /*
10050 run_query() can execute a query partially, depending on the flags.
10051 QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send
10052 the query and read the result some time later when reap instruction
10053 is given on this connection.
10054 */
10055
1/2
✓ Branch 0 taken 22486 times.
✗ Branch 1 not taken.
22486 run_query(cur_con, command, QUERY_SEND_FLAG);
10056 22486 command_executed++;
10057 22486 command->last_argument = command->end;
10058 22486 break;
10059 666431 case Q_ERROR:
10060
1/2
✓ Branch 0 taken 666392 times.
✗ Branch 1 not taken.
666431 do_error(command);
10061 666392 break;
10062 32552 case Q_REPLACE:
10063
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32552 do_get_replace(command);
10064 32534 break;
10065 10426 case Q_REPLACE_REGEX:
10066
1/2
✓ Branch 0 taken 10405 times.
✗ Branch 1 not taken.
10426 do_get_replace_regex(command);
10067 10405 break;
10068 12288 case Q_REPLACE_COLUMN:
10069
1/2
✓ Branch 0 taken 12273 times.
✗ Branch 1 not taken.
12288 do_get_replace_column(command);
10070 12273 break;
10071 319 case Q_REPLACE_NUMERIC_ROUND:
10072
1/2
✓ Branch 0 taken 310 times.
✗ Branch 1 not taken.
319 do_get_replace_numeric_round(command);
10073 310 break;
10074 232 case Q_SAVE_MASTER_POS:
10075
1/2
✓ Branch 0 taken 232 times.
✗ Branch 1 not taken.
232 do_save_master_pos();
10076 232 break;
10077 185 case Q_SYNC_WITH_MASTER:
10078
1/2
✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
185 do_sync_with_master(command);
10079 179 break;
10080 1555 case Q_SYNC_SLAVE_WITH_MASTER: {
10081
1/2
✓ Branch 0 taken 1555 times.
✗ Branch 1 not taken.
1555 do_save_master_pos();
10082
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1519 times.
1555 if (*command->first_argument)
10083
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 select_connection(command);
10084 else
10085
1/2
✓ Branch 0 taken 1519 times.
✗ Branch 1 not taken.
1519 select_connection_name("slave");
10086
1/2
✓ Branch 0 taken 1555 times.
✗ Branch 1 not taken.
1555 do_sync_with_master2(command, 0);
10087 1555 break;
10088 }
10089 100041498 case Q_COMMENT: {
10090 100041498 command->last_argument = command->end;
10091
10092 /* Don't output comments in v1 */
10093
1/2
✓ Branch 0 taken 100041498 times.
✗ Branch 1 not taken.
100041498 if (opt_result_format_version == 1) break;
10094
10095 /* Don't output comments if query logging is off */
10096 if (disable_query_log) break;
10097
10098 /* Write comment's with two starting #'s to result file */
10099 const char *p = command->query;
10100 if (p && *p == '#' && *(p + 1) == '#') {
10101 dynstr_append_mem(&ds_res, command->query, command->query_len);
10102 dynstr_append(&ds_res, "\n");
10103 }
10104 break;
10105 }
10106 10242275 case Q_EMPTY_LINE:
10107 /* Don't output newline in v1 */
10108
1/2
✓ Branch 0 taken 10242275 times.
✗ Branch 1 not taken.
10242275 if (opt_result_format_version == 1) break;
10109
10110 /* Don't output newline if query logging is off */
10111 if (disable_query_log) break;
10112
10113 dynstr_append(&ds_res, "\n");
10114 break;
10115 8 case Q_PING:
10116
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 handle_command_error(command, mysql_ping(&cur_con->mysql));
10117 8 break;
10118 31 case Q_RESET_CONNECTION:
10119
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
31 do_reset_connection();
10120
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 global_attrs->clear();
10121 30 break;
10122 10 case Q_QUERY_ATTRIBUTES:
10123
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 do_query_attributes(command);
10124 10 break;
10125 28 case Q_SEND_SHUTDOWN:
10126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (opt_offload_count_file) {
10127 // Save the value of secondary engine execution status
10128 // before shutting down the server.
10129 if (secondary_engine->offload_count(&cur_con->mysql, "after"))
10130 cleanup_and_exit(1);
10131 }
10132
10133 28 handle_command_error(
10134
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 command, mysql_query_wrapper(&cur_con->mysql, "shutdown"));
10135 28 break;
10136 3549 case Q_SHUTDOWN_SERVER:
10137
1/2
✓ Branch 0 taken 3549 times.
✗ Branch 1 not taken.
3549 do_shutdown_server(command);
10138 3549 break;
10139 23488 case Q_EXEC:
10140 case Q_EXECW:
10141
1/2
✓ Branch 0 taken 23469 times.
✗ Branch 1 not taken.
23488 do_exec(command, false);
10142 23469 command_executed++;
10143 23469 break;
10144 10648 case Q_EXEC_BACKGROUND:
10145
1/2
✓ Branch 0 taken 10648 times.
✗ Branch 1 not taken.
10648 do_exec(command, true);
10146 10648 command_executed++;
10147 10648 break;
10148 case Q_START_TIMER:
10149 /* Overwrite possible earlier start of timer */
10150 timer_start = timer_now();
10151 break;
10152 case Q_END_TIMER:
10153 /* End timer before ending mysqltest */
10154 timer_output();
10155 break;
10156 271 case Q_CHARACTER_SET:
10157
1/2
✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
271 do_set_charset(command);
10158 271 break;
10159 280 case Q_DISABLE_PS_PROTOCOL:
10160
1/2
✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
280 set_property(command, P_PS, false);
10161 /* Close any open statements */
10162
1/2
✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
280 close_statements();
10163 280 break;
10164 249 case Q_ENABLE_PS_PROTOCOL:
10165
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 set_property(command, P_PS, ps_protocol);
10166 249 break;
10167 10728 case Q_DISABLE_RECONNECT:
10168
1/2
✓ Branch 0 taken 10728 times.
✗ Branch 1 not taken.
10728 set_reconnect(&cur_con->mysql, 0);
10169 10728 break;
10170 10749 case Q_ENABLE_RECONNECT:
10171
1/2
✓ Branch 0 taken 10749 times.
✗ Branch 1 not taken.
10749 set_reconnect(&cur_con->mysql, 1);
10172 10749 enable_async_client = false;
10173 /* Close any open statements - no reconnect, need new prepare */
10174
1/2
✓ Branch 0 taken 10749 times.
✗ Branch 1 not taken.
10749 close_statements();
10175 10749 break;
10176 35 case Q_ENABLE_ASYNC_CLIENT:
10177
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 set_property(command, P_ASYNC, true);
10178 35 break;
10179 35 case Q_DISABLE_ASYNC_CLIENT:
10180
1/2
✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
35 set_property(command, P_ASYNC, false);
10181 35 break;
10182 75 case Q_DISABLE_TESTCASE:
10183
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 3 times.
75 if (testcase_disabled == 0)
10184
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
72 do_disable_testcase(command);
10185 else
10186 3 die("Test case is already disabled.");
10187 63 break;
10188 60 case Q_ENABLE_TESTCASE:
10189 // Ensure we don't get testcase_disabled < 0 as this would
10190 // accidentally disable code we don't want to have disabled.
10191
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 3 times.
60 if (testcase_disabled == 1)
10192 57 testcase_disabled = false;
10193 else
10194 3 die("Test case is already enabled.");
10195 57 break;
10196 16 case Q_DIE:
10197 /* Abort test with error code and error message */
10198 16 die("%s", command->first_argument);
10199 break;
10200 54 case Q_EXIT:
10201 /* Stop processing any more commands */
10202 54 abort_flag = true;
10203 54 break;
10204 13539 case Q_SKIP: {
10205 DYNAMIC_STRING ds_skip_msg;
10206
1/2
✓ Branch 0 taken 13539 times.
✗ Branch 1 not taken.
13539 init_dynamic_string(&ds_skip_msg, nullptr, command->query_len);
10207
10208 // Evaluate the skip message
10209
1/2
✓ Branch 0 taken 13539 times.
✗ Branch 1 not taken.
13539 do_eval(&ds_skip_msg, command->first_argument, command->end, false);
10210
10211 char skip_msg[FN_REFLEN];
10212
1/2
✓ Branch 0 taken 13539 times.
✗ Branch 1 not taken.
13539 if (ds_skip_msg.length > 0) {
10213
1/2
✓ Branch 0 taken 13539 times.
✗ Branch 1 not taken.
13539 strmake(skip_msg, ds_skip_msg.str, FN_REFLEN - 1);
10214 } else {
10215 skip_msg[0] = '\0';
10216 }
10217
10218
1/2
✓ Branch 0 taken 13539 times.
✗ Branch 1 not taken.
13539 dynstr_free(&ds_skip_msg);
10219
10220
2/2
✓ Branch 0 taken 13536 times.
✓ Branch 1 taken 3 times.
13539 if (!no_skip) {
10221 // --no-skip option is disabled, skip the test case
10222 13536 abort_not_supported_test("%s", skip_msg);
10223 } else {
10224 3 const char *path = cur_file->file_name;
10225 3 const char *fn = get_filename_from_path(path);
10226
10227 // Check if the file is in excluded list
10228
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (excluded_string && strstr(excluded_string, fn)) {
10229 // File is present in excluded list, skip the test case
10230 abort_not_supported_test("%s", skip_msg);
10231 } else {
10232 // File is not present in excluded list, ignore the skip
10233 // and continue running the test case
10234 3 command->last_argument = command->end;
10235 3 skip_ignored = true; // Mark as noskip pass or fail.
10236 }
10237 }
10238 3 } break;
10239 191 case Q_OUTPUT: {
10240 static DYNAMIC_STRING ds_to_file;
10241 191 const struct command_arg output_file_args[] = {
10242 {"to_file", ARG_STRING, true, &ds_to_file, "Output filename"}};
10243
1/2
✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
191 check_command_args(command, command->first_argument, output_file_args,
10244 1, ' ');
10245
1/2
✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
191 strmake(output_file, ds_to_file.str, FN_REFLEN);
10246
1/2
✓ Branch 0 taken 191 times.
✗ Branch 1 not taken.
191 dynstr_free(&ds_to_file);
10247 191 break;
10248 }
10249
10250 26360917 default:
10251 26360917 processed = 0;
10252 26360917 break;
10253 }
10254 }
10255
10256
2/2
✓ Branch 0 taken 1659920280 times.
✓ Branch 1 taken 164092599 times.
1824012879 if (!processed) {
10257 1659920280 current_line_inc = 0;
10258
5/5
✓ Branch 0 taken 8557137 times.
✓ Branch 1 taken 170839582 times.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 179382994 times.
✓ Branch 4 taken 1301140367 times.
1659920280 switch (command->type) {
10259 8557137 case Q_WHILE:
10260
1/2
✓ Branch 0 taken 8557122 times.
✗ Branch 1 not taken.
8557137 do_block(cmd_while, command);
10261 8557122 break;
10262 170839582 case Q_IF:
10263
1/2
✓ Branch 0 taken 170839564 times.
✗ Branch 1 not taken.
170839582 do_block(cmd_if, command);
10264 170839564 break;
10265 200 case Q_ASSERT:
10266
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
200 do_block(cmd_assert, command);
10267 176 break;
10268 179382994 case Q_END_BLOCK:
10269
1/2
✓ Branch 0 taken 179382985 times.
✗ Branch 1 not taken.
179382994 do_done(command);
10270 179382985 break;
10271 1301140367 default:
10272 1301140367 current_line_inc = 1;
10273 1301140367 break;
10274 }
10275 } else
10276
1/2
✓ Branch 0 taken 164092587 times.
✗ Branch 1 not taken.
164092599 check_eol_junk(command->last_argument);
10277
10278
4/4
✓ Branch 0 taken 1821589494 times.
✓ Branch 1 taken 2423307 times.
✓ Branch 2 taken 998338648 times.
✓ Branch 3 taken 823250846 times.
1824012801 if (command->type != Q_ERROR && command->type != Q_COMMENT &&
10279
4/4
✓ Branch 0 taken 827499084 times.
✓ Branch 1 taken 170839564 times.
✓ Branch 2 taken 648116099 times.
✓ Branch 3 taken 179382985 times.
998338648 command->type != Q_IF && command->type != Q_END_BLOCK) {
10280 // As soon as any non "error" command or comment has been executed,
10281 // the array with expected errors should be cleared
10282 648116099 expected_errors->clear_list();
10283 }
10284
10285
4/4
✓ Branch 0 taken 1817949237 times.
✓ Branch 1 taken 6063564 times.
✓ Branch 2 taken 151686 times.
✓ Branch 3 taken 1817797551 times.
1824012801 if (command_executed != last_command_executed || command->used_replace) {
10286 /*
10287 As soon as any command has been executed,
10288 the replace structures should be cleared
10289 */
10290
1/2
✓ Branch 0 taken 6215250 times.
✗ Branch 1 not taken.
6215250 free_all_replace();
10291
10292 /* Also reset "sorted_result", "lowercase" and "skip_if_hypergraph"*/
10293 6215250 display_result_sorted = false;
10294 6215250 display_result_lower = false;
10295 6215250 skip_if_hypergraph = false;
10296 }
10297 1824012801 last_command_executed = command_executed;
10298
10299 1824012801 parser.current_line += current_line_inc;
10300
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1824012801 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1824012801 if (opt_mark_progress) mark_progress(&progress_file, parser.current_line);
10301
10302 // Write result from command to log file immediately.
10303
1/2
✓ Branch 0 taken 1824012801 times.
✗ Branch 1 not taken.
1824012801 flush_ds_res();
10304 }
10305
10306 35824 start_lineno = 0;
10307
1/2
✓ Branch 0 taken 35824 times.
✗ Branch 1 not taken.
35824 verbose_msg("... Done processing test commands.");
10308
10309
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 35821 times.
35824 if (testcase_disabled) die("Test ended with test case execution disabled.");
10310
10311
5/6
✓ Branch 0 taken 35812 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35812 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 35812 times.
35821 if (disable_warnings || disabled_warnings->count())
10312 9 die("The test didn't enable all the disabled warnings, enable "
10313 "all of them before end of the test.");
10314
10315 35812 bool empty_result = false;
10316
10317 /*
10318 The whole test has been executed _sucessfully_.
10319 Time to compare result or save it to record file.
10320 The entire output from test is in the log file
10321 */
10322
2/2
✓ Branch 0 taken 35807 times.
✓ Branch 1 taken 5 times.
35812 if (log_file.bytes_written()) {
10323
2/2
✓ Branch 0 taken 35747 times.
✓ Branch 1 taken 60 times.
35807 if (result_file_name) {
10324 /* A result file has been specified */
10325
10326
2/2
✓ Branch 0 taken 13740 times.
✓ Branch 1 taken 22007 times.
35747 if (record) {
10327 /* Recording */
10328
10329 /* save a copy of the log to result file */
10330
2/4
✓ Branch 0 taken 13740 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13740 times.
13740 if (my_copy(log_file.file_name(), result_file_name, MYF(0)) != 0)
10331 die("Failed to copy '%s' to '%s', errno: %d", log_file.file_name(),
10332 result_file_name, errno);
10333
10334 } else {
10335 /* Check that the output from test is equal to result file */
10336
1/2
✓ Branch 0 taken 21996 times.
✗ Branch 1 not taken.
22007 check_result();
10337 }
10338 }
10339 } else {
10340 /* Empty output is an error *unless* we also have an empty result file */
10341
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
7 if (!result_file_name || record ||
10342
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 compare_files(log_file.file_name(), result_file_name)) {
10343 3 die("The test didn't produce any output");
10344 } else {
10345 2 empty_result = true; /* Meaning empty was expected */
10346 }
10347 }
10348
10349
4/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35797 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
35798 if (!command_executed && result_file_name && !empty_result)
10350 die("No queries executed but non-empty result file found!");
10351
10352
1/2
✓ Branch 0 taken 35798 times.
✗ Branch 1 not taken.
35798 verbose_msg("Test has succeeded!");
10353
1/2
✓ Branch 0 taken 35798 times.
✗ Branch 1 not taken.
35798 timer_output();
10354 /* Yes, if we got this far the test has succeeded! Sakila smiles */
10355 35798 cleanup_and_exit(0);
10356 return 0; /* Keep compiler happy too */
10357 }
10358
10359 /*
10360 A primitive timer that give results in milliseconds if the
10361 --timer-file=<filename> is given. The timer result is written
10362 to that file when the result is available. To not confuse
10363 mysql-test-run with an old obsolete result, we remove the file
10364 before executing any commands. The time we measure is
10365
10366 - If no explicit 'start_timer' or 'end_timer' is given in the
10367 test case, the timer measure how long we execute in mysqltest.
10368
10369 - If only 'start_timer' is given we measure how long we execute
10370 from that point until we terminate mysqltest.
10371
10372 - If only 'end_timer' is given we measure how long we execute
10373 from that we enter mysqltest to the 'end_timer' is command is
10374 executed.
10375
10376 - If both 'start_timer' and 'end_timer' are given we measure
10377 the time between executing the two commands.
10378 */
10379
10380 35798 void timer_output(void) {
10381
2/2
✓ Branch 0 taken 9359 times.
✓ Branch 1 taken 26439 times.
35798 if (timer_file) {
10382 char buf[32], *end;
10383 9359 ulonglong timer = timer_now() - timer_start;
10384
1/2
✓ Branch 0 taken 9359 times.
✗ Branch 1 not taken.
9359 end = longlong10_to_str(timer, buf, 10);
10385
1/2
✓ Branch 0 taken 9359 times.
✗ Branch 1 not taken.
9359 str_to_file(timer_file, buf, (int)(end - buf));
10386 /* Timer has been written to the file, don't use it anymore */
10387 9359 timer_file = nullptr;
10388 }
10389 35798 }
10390
10391 59462 ulonglong timer_now(void) { return my_micro_time() / 1000; }
10392
10393 /*
10394 Get arguments for replace_columns. The syntax is:
10395 replace-column column_number to_string [column_number to_string ...]
10396 Where each argument may be quoted with ' or "
10397 A argument may also be a variable, in which case the value of the
10398 variable is replaced.
10399 */
10400
10401 12288 void do_get_replace_column(struct st_command *command) {
10402 12288 const char *from = command->first_argument;
10403 char *buff, *start;
10404
1/2
✓ Branch 0 taken 12288 times.
✗ Branch 1 not taken.
12288 DBUG_TRACE;
10405
10406
1/2
✓ Branch 0 taken 12288 times.
✗ Branch 1 not taken.
12288 free_replace_column();
10407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12288 times.
12288 if (!*from) die("Missing argument in %s", command->query);
10408
10409 /* Allocate a buffer for results */
10410
1/2
✓ Branch 0 taken 12288 times.
✗ Branch 1 not taken.
12288 start = buff = (char *)my_malloc(PSI_NOT_INSTRUMENTED, std::strlen(from) + 1,
10411 MYF(MY_WME | MY_FAE));
10412
2/2
✓ Branch 0 taken 133081 times.
✓ Branch 1 taken 12273 times.
145354 while (*from) {
10413 char *to;
10414 uint column_number;
10415
1/2
✓ Branch 0 taken 133081 times.
✗ Branch 1 not taken.
133081 to = get_string(&buff, &from, command);
10416
5/6
✓ Branch 0 taken 133069 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 133069 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 133069 times.
133081 if (!(column_number = atoi(to)) || column_number > MAX_COLUMNS)
10417 12 die("Wrong column number to replace_column in '%s'", command->query);
10418
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 133066 times.
133069 if (!*from)
10419 3 die("Wrong number of arguments to replace_column in '%s'",
10420 command->query);
10421
1/2
✓ Branch 0 taken 133066 times.
✗ Branch 1 not taken.
133066 to = get_string(&buff, &from, command);
10422
1/2
✓ Branch 0 taken 133066 times.
✗ Branch 1 not taken.
133066 my_free(replace_column[column_number - 1]);
10423 266132 replace_column[column_number - 1] =
10424
1/2
✓ Branch 0 taken 133066 times.
✗ Branch 1 not taken.
133066 my_strdup(PSI_NOT_INSTRUMENTED, to, MYF(MY_WME | MY_FAE));
10425 133066 max_replace_column = std::max(max_replace_column, column_number);
10426 }
10427
1/2
✓ Branch 0 taken 12273 times.
✗ Branch 1 not taken.
12273 my_free(start);
10428 12273 command->last_argument = command->end;
10429 12273 }
10430
10431 6277664 void free_replace_column() {
10432 uint i;
10433
2/2
✓ Branch 0 taken 289172 times.
✓ Branch 1 taken 6277664 times.
6566836 for (i = 0; i < max_replace_column; i++) {
10434
2/2
✓ Branch 0 taken 133062 times.
✓ Branch 1 taken 156110 times.
289172 if (replace_column[i]) {
10435 133062 my_free(replace_column[i]);
10436 133062 replace_column[i] = nullptr;
10437 }
10438 }
10439 6277664 max_replace_column = 0;
10440 6277664 }
10441
10442 /*
10443 Functions to round numeric results.
10444
10445 SYNOPSIS
10446 do_get_replace_numeric_round()
10447 command - command handle
10448
10449 DESCRIPTION
10450 replace_numeric_round <precision>
10451
10452 where precision is the number of digits after the decimal point
10453 that the result will be rounded off to. The precision can only
10454 be a number between 0 and 16.
10455 eg. replace_numeric_round 10;
10456 Numbers which are > 1e10 or < -1e10 are represented using the
10457 exponential notation after they are rounded off.
10458 Trailing zeroes after the decimal point are removed from the
10459 numbers.
10460 If the precision is 0, then the value is rounded off to the
10461 nearest whole number.
10462 */
10463 319 void do_get_replace_numeric_round(struct st_command *command) {
10464 DYNAMIC_STRING ds_round;
10465 319 const struct command_arg numeric_arg = {
10466 319 "precision", ARG_STRING, true, &ds_round, "Number of decimal precision"};
10467
1/2
✓ Branch 0 taken 319 times.
✗ Branch 1 not taken.
319 DBUG_TRACE;
10468
10469
1/2
✓ Branch 0 taken 316 times.
✗ Branch 1 not taken.
319 check_command_args(command, command->first_argument, &numeric_arg,
10470 sizeof(numeric_arg) / sizeof(struct command_arg), ' ');
10471
10472 // Parse the argument string to get the precision
10473 316 long int v = 0;
10474
3/4
✓ Branch 0 taken 316 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 310 times.
316 if (str2int(ds_round.str, 10, 0, REPLACE_ROUND_MAX, &v) == NullS)
10475 6 die("A number between 0 and %d is required for the precision "
10476 "in replace_numeric_round",
10477 REPLACE_ROUND_MAX);
10478
10479 310 glob_replace_numeric_round = (int)v;
10480
1/2
✓ Branch 0 taken 310 times.
✗ Branch 1 not taken.
310 dynstr_free(&ds_round);
10481 310 }
10482
10483 6265376 void free_replace_numeric_round() { glob_replace_numeric_round = -1; }
10484
10485 /*
10486 Round the digits after the decimal point to the specified precision
10487 by iterating through the result set element, identifying the part to
10488 be rounded off, and rounding that part off.
10489 */
10490 3707 void replace_numeric_round_append(int round, DYNAMIC_STRING *result,
10491 const char *from, size_t len) {
10492
2/2
✓ Branch 0 taken 26893 times.
✓ Branch 1 taken 373 times.
27266 while (len > 0) {
10493 // Move pointer to the start of the numeric values
10494 26893 size_t size = strcspn(from, "0123456789");
10495
2/2
✓ Branch 0 taken 24890 times.
✓ Branch 1 taken 2003 times.
26893 if (size > 0) {
10496 24890 dynstr_append_mem(result, from, size);
10497 24890 from += size;
10498 24890 len -= size;
10499 }
10500
10501 /*
10502 Move the pointer to the end of the numeric values and the
10503 the start of the non-numeric values such as "." and "e"
10504 */
10505 26893 size = strspn(from, "0123456789");
10506 26893 int r = round;
10507
10508 /*
10509 If result from one of the rows of the result set is null,
10510 break the loop
10511 */
10512
2/2
✓ Branch 0 taken 3334 times.
✓ Branch 1 taken 23559 times.
26893 if (*(from + size) == 0) {
10513 3334 dynstr_append_mem(result, from, size);
10514 3334 break;
10515 }
10516
10517
2/3
✓ Branch 0 taken 12587 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10972 times.
23559 switch (*(from + size)) {
10518 // double/float
10519 12587 case '.':
10520 size_t size1;
10521 12587 size1 = strspn(from + size + 1, "0123456789");
10522
10523 /*
10524 Restrict rounding to less than the
10525 the existing precision to avoid 1.2 being replaced
10526 to 1.2000000
10527 */
10528
2/2
✓ Branch 0 taken 344 times.
✓ Branch 1 taken 12243 times.
12587 if (size1 < (size_t)r) r = size1;
10529 // fallthrough: all cases till next break are executed
10530 [[fallthrough]];
10531 case 'e':
10532 case 'E':
10533
2/2
✓ Branch 0 taken 12513 times.
✓ Branch 1 taken 74 times.
12587 if (isdigit(*(from + size + 1))) {
10534 char *end;
10535 12513 double val = strtod(from, &end);
10536
1/2
✓ Branch 0 taken 12513 times.
✗ Branch 1 not taken.
12513 if (end != nullptr) {
10537
3/4
✓ Branch 0 taken 12510 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 12510 times.
✗ Branch 3 not taken.
12513 const char *format = (val < 1e10 && val > -1e10) ? "%.*f" : "%.*e";
10538 char buf[40];
10539
10540 12513 size = snprintf(buf, sizeof(buf), format, r, val);
10541
5/6
✓ Branch 0 taken 12510 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 12510 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11394 times.
✓ Branch 5 taken 1116 times.
12513 if (val < 1e10 && val > -1e10 && r > 0) {
10542 /*
10543 2.0000000 need to be represented as 2 for consistency
10544 2.0010000 also becomes 2.001
10545 */
10546
2/2
✓ Branch 0 taken 2621 times.
✓ Branch 1 taken 11394 times.
14015 while (buf[size - 1] == '0') size--;
10547
10548 // don't leave 100. trailing
10549
2/2
✓ Branch 0 taken 451 times.
✓ Branch 1 taken 10943 times.
11394 if (buf[size - 1] == '.') size--;
10550 }
10551
1/2
✓ Branch 0 taken 12513 times.
✗ Branch 1 not taken.
12513 dynstr_append_mem(result, buf, size);
10552 12513 len -= (end - from);
10553 12513 from = end;
10554 12513 break;
10555 }
10556 }
10557
10558 /*
10559 This is because strtod didn't convert or there wasn't digits after
10560 [.eE] so output without changing
10561 */
10562 74 dynstr_append_mem(result, from, size);
10563 74 from += size;
10564 74 len -= size;
10565 74 break;
10566 // int
10567 10972 default:
10568 10972 dynstr_append_mem(result, from, size);
10569 10972 from += size;
10570 10972 len -= size;
10571 10972 break;
10572 }
10573 }
10574 3707 }
10575
10576 /****************************************************************************/
10577 /*
10578 Replace functions
10579 */
10580
10581 /* Definitions for replace result */
10582
10583 struct POINTER_ARRAY { /* when using array-strings */
10584 TYPELIB typelib; /* Pointer to strings */
10585 uchar *str{nullptr}; /* Strings is here */
10586 uint8 *flag{nullptr}; /* Flag about each var. */
10587 uint array_allocs{0}, max_count{0}, length{0}, max_length{0};
10588 };
10589
10590 REPLACE *init_replace(const char **from, const char **to, uint count,
10591 const char *word_end_chars);
10592 int insert_pointer_name(POINTER_ARRAY *pa, char *name);
10593 void free_pointer_array(POINTER_ARRAY *pa);
10594
10595 /*
10596 Get arguments for replace. The syntax is:
10597 replace from to [from to ...]
10598 Where each argument may be quoted with ' or "
10599 A argument may also be a variable, in which case the value of the
10600 variable is replaced.
10601 */
10602
10603 32552 void do_get_replace(struct st_command *command) {
10604 uint i;
10605 32552 const char *from = command->first_argument;
10606 char *buff, *start;
10607 char word_end_chars[256], *pos;
10608 32552 POINTER_ARRAY to_array, from_array;
10609
1/2
✓ Branch 0 taken 32552 times.
✗ Branch 1 not taken.
32552 DBUG_TRACE;
10610
10611
1/2
✓ Branch 0 taken 32552 times.
✗ Branch 1 not taken.
32552 free_replace();
10612
10613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32552 times.
32552 if (!*from) die("Missing argument in %s", command->query);
10614
1/2
✓ Branch 0 taken 32552 times.
✗ Branch 1 not taken.
32552 start = buff = (char *)my_malloc(PSI_NOT_INSTRUMENTED, std::strlen(from) + 1,
10615 MYF(MY_WME | MY_FAE));
10616
2/2
✓ Branch 0 taken 53007 times.
✓ Branch 1 taken 32534 times.
85541 while (*from) {
10617 53007 char *to = buff;
10618
1/2
✓ Branch 0 taken 53007 times.
✗ Branch 1 not taken.
53007 to = get_string(&buff, &from, command);
10619
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 52989 times.
53007 if (!*from)
10620 18 die("Wrong number of arguments to replace_result in '%s'",
10621 command->query);
10622 #ifdef _WIN32
10623 fix_win_paths(to, from - to);
10624 #endif
10625
1/2
✓ Branch 0 taken 52989 times.
✗ Branch 1 not taken.
52989 insert_pointer_name(&from_array, to);
10626
1/2
✓ Branch 0 taken 52989 times.
✗ Branch 1 not taken.
52989 to = get_string(&buff, &from, command);
10627
1/2
✓ Branch 0 taken 52989 times.
✗ Branch 1 not taken.
52989 insert_pointer_name(&to_array, to);
10628 }
10629
2/2
✓ Branch 0 taken 8296170 times.
✓ Branch 1 taken 32534 times.
8328704 for (i = 1, pos = word_end_chars; i < 256; i++)
10630
2/2
✓ Branch 0 taken 195258 times.
✓ Branch 1 taken 8100912 times.
8296170 if (my_isspace(charset_info, i)) *pos++ = i;
10631 32534 *pos = 0; /* End pointer */
10632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32534 times.
32534 if (!(glob_replace = init_replace(
10633 from_array.typelib.type_names, to_array.typelib.type_names,
10634
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 (uint)from_array.typelib.count, word_end_chars)))
10635 die("Can't initialize replace from '%s'", command->query);
10636
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 free_pointer_array(&from_array);
10637
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 free_pointer_array(&to_array);
10638
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 my_free(start);
10639 32534 command->last_argument = command->end;
10640 32534 }
10641
10642 6297928 void free_replace() {
10643
1/2
✓ Branch 0 taken 6297928 times.
✗ Branch 1 not taken.
6297928 DBUG_TRACE;
10644
1/2
✓ Branch 0 taken 6297928 times.
✗ Branch 1 not taken.
6297928 my_free(glob_replace);
10645 6297928 glob_replace = nullptr;
10646 6297928 }
10647
10648 struct REPLACE {
10649 int found;
10650 REPLACE *next[256];
10651 };
10652
10653 struct REPLACE_STRING {
10654 int found;
10655 const char *replace_string;
10656 uint to_offset;
10657 int from_offset;
10658 };
10659
10660 270393 void replace_strings_append(REPLACE *rep, DYNAMIC_STRING *ds, const char *str,
10661 size_t len [[maybe_unused]]) {
10662 REPLACE *rep_pos;
10663 REPLACE_STRING *rep_str;
10664 const char *start, *from;
10665
1/2
✓ Branch 0 taken 270393 times.
✗ Branch 1 not taken.
270393 DBUG_TRACE;
10666
10667 270393 start = from = str;
10668 270393 rep_pos = rep + 1;
10669 for (;;) {
10670 /* Loop through states */
10671
3/8
✓ Branch 0 taken 301004 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 301004 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 301004 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
301004 DBUG_PRINT("info", ("Looping through states"));
10672
2/2
✓ Branch 0 taken 10170700 times.
✓ Branch 1 taken 301004 times.
10471704 while (!rep_pos->found) rep_pos = rep_pos->next[(uchar)*from++];
10673
10674 /* Does this state contain a string to be replaced */
10675
2/2
✓ Branch 0 taken 267352 times.
✓ Branch 1 taken 33652 times.
301004 if (!(rep_str = ((REPLACE_STRING *)rep_pos))->replace_string) {
10676 /* No match found */
10677
1/2
✓ Branch 0 taken 267352 times.
✗ Branch 1 not taken.
267352 dynstr_append_mem(ds, start, from - start - 1);
10678
3/8
✓ Branch 0 taken 267352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267352 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 267352 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
267352 DBUG_PRINT("exit",
10679 ("Found no more string to replace, appended: %s", start));
10680 267352 return;
10681 }
10682
10683 /* Found a string that needs to be replaced */
10684
3/8
✓ Branch 0 taken 33652 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33652 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33652 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
33652 DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s",
10685 rep_str->found, rep_str->to_offset,
10686 rep_str->from_offset, rep_str->replace_string));
10687
10688 /* Append part of original string before replace string */
10689
1/2
✓ Branch 0 taken 33652 times.
✗ Branch 1 not taken.
33652 dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start);
10690
10691 /* Append replace string */
10692
1/2
✓ Branch 0 taken 33652 times.
✗ Branch 1 not taken.
33652 dynstr_append_mem(ds, rep_str->replace_string,
10693 std::strlen(rep_str->replace_string));
10694
10695
5/6
✓ Branch 0 taken 3041 times.
✓ Branch 1 taken 30611 times.
✓ Branch 2 taken 3041 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3041 times.
✓ Branch 5 taken 30611 times.
33652 if (!*(from -= rep_str->from_offset) && rep_pos->found != 2) {
10696 /* End of from string */
10697
3/8
✓ Branch 0 taken 3041 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3041 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3041 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3041 DBUG_PRINT("exit", ("Found end of from string"));
10698 3041 return;
10699 }
10700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30611 times.
30611 assert(from <= str + len);
10701 30611 start = from;
10702 30611 rep_pos = rep;
10703 }
10704 270393 }
10705
10706 /*
10707 Regex replace functions
10708 */
10709
10710 /*
10711 Finds the next (non-escaped) '/' in the expression.
10712 (If the character '/' is needed, it can be escaped using '\'.)
10713 */
10714
10715 #define PARSE_REGEX_ARG \
10716 while (p < expr_end) { \
10717 char c = *p; \
10718 if (c == '/') { \
10719 if (last_c == '\\') { \
10720 buf_p[-1] = '/'; \
10721 } else { \
10722 *buf_p++ = 0; \
10723 break; \
10724 } \
10725 } else \
10726 *buf_p++ = c; \
10727 \
10728 last_c = c; \
10729 p++; \
10730 }
10731
10732 /**
10733 Initializes the regular substitution expression to be used in the
10734 result output of test.
10735
10736 @param expr Pointer to string having regular expression to be used
10737 for substitution.
10738 @retval st_replace_regex structure with pairs of substitutions.
10739 */
10740 10237 static struct st_replace_regex *init_replace_regex(const char *expr) {
10741 struct st_replace_regex *res;
10742 char *buf;
10743 const char *expr_end;
10744 const char *p;
10745 char *buf_p;
10746 10237 size_t expr_len = std::strlen(expr);
10747 10237 char last_c = 0;
10748 struct st_regex reg;
10749
10750 /* my_malloc() will die on fail with MY_FAE */
10751
1/2
✓ Branch 0 taken 10237 times.
✗ Branch 1 not taken.
10237 void *rawmem = my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*res) + expr_len,
10752 MYF(MY_FAE + MY_WME));
10753
1/2
✓ Branch 0 taken 10237 times.
✗ Branch 1 not taken.
10237 res = new (rawmem) st_replace_regex;
10754
10755 10237 buf = (char *)res + sizeof(*res);
10756 10237 expr_end = expr + expr_len;
10757 10237 p = expr;
10758 10237 buf_p = buf;
10759
10760 /* for each regexp substitution statement */
10761
2/2
✓ Branch 0 taken 26020 times.
✓ Branch 1 taken 8993 times.
35013 while (p < expr_end) {
10762 26020 memset(&reg, 0, sizeof(reg));
10763 /* find the start of the statement */
10764
2/2
✓ Branch 0 taken 64336 times.
✓ Branch 1 taken 1238 times.
65574 while (p < expr_end) {
10765
2/2
✓ Branch 0 taken 24782 times.
✓ Branch 1 taken 39554 times.
64336 if (*p == '/') break;
10766 39554 p++;
10767 }
10768
10769
5/6
✓ Branch 0 taken 24782 times.
✓ Branch 1 taken 1238 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24782 times.
✓ Branch 4 taken 1238 times.
✓ Branch 5 taken 24782 times.
26020 if (p == expr_end || ++p == expr_end) {
10770
3/4
✓ Branch 0 taken 1238 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1223 times.
✓ Branch 3 taken 15 times.
1238 if (res->regex_arr.size())
10771 1223 break;
10772 else
10773 15 goto err;
10774 }
10775 /* we found the start */
10776 24782 reg.pattern = buf_p;
10777
10778 /* Find first argument -- pattern string to be removed */
10779
6/6
✓ Branch 0 taken 31200 times.
✓ Branch 1 taken 737911 times.
✓ Branch 2 taken 6421 times.
✓ Branch 3 taken 24779 times.
✓ Branch 4 taken 769111 times.
✓ Branch 5 taken 3 times.
769114 PARSE_REGEX_ARG
10780
10781
5/6
✓ Branch 0 taken 24779 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24779 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 24779 times.
24782 if (p == expr_end || ++p == expr_end) goto err;
10782
10783 /* buf_p now points to the replacement pattern terminated with \0 */
10784 24779 reg.replace = buf_p;
10785
10786 /* Find second argument -- replace string to replace pattern */
10787
6/6
✓ Branch 0 taken 25444 times.
✓ Branch 1 taken 451934 times.
✓ Branch 2 taken 668 times.
✓ Branch 3 taken 24776 times.
✓ Branch 4 taken 477378 times.
✓ Branch 5 taken 3 times.
477381 PARSE_REGEX_ARG
10788
10789
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24776 times.
24779 if (p == expr_end) goto err;
10790
10791 /* skip the ending '/' in the statement */
10792 24776 p++;
10793
10794 /* Check if we should do matching case insensitive */
10795
4/4
✓ Branch 0 taken 15783 times.
✓ Branch 1 taken 8993 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 15771 times.
24776 if (p < expr_end && *p == 'i') reg.icase = 1;
10796
10797 /* done parsing the statement, now place it in regex_arr */
10798
2/4
✓ Branch 0 taken 24776 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24776 times.
24776 if (res->regex_arr.push_back(reg)) die("Out of memory");
10799 }
10800 10216 res->odd_buf_len = res->even_buf_len = 8192;
10801
1/2
✓ Branch 0 taken 10216 times.
✗ Branch 1 not taken.
10216 res->even_buf = (char *)my_malloc(PSI_NOT_INSTRUMENTED, res->even_buf_len,
10802 MYF(MY_WME + MY_FAE));
10803
1/2
✓ Branch 0 taken 10216 times.
✗ Branch 1 not taken.
10216 res->odd_buf = (char *)my_malloc(PSI_NOT_INSTRUMENTED, res->odd_buf_len,
10804 MYF(MY_WME + MY_FAE));
10805 10216 res->buf = res->even_buf;
10806
10807 10216 return res;
10808
10809 21 err:
10810
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 my_free(res);
10811 21 die("Error parsing replace_regex \"%s\"", expr);
10812 return nullptr;
10813 }
10814
10815 /*
10816 Parse the regular expression to be used in all result files
10817 from now on.
10818
10819 The syntax is --replace_regex /from/to/i /from/to/i ...
10820 i means case-insensitive match. If omitted, the match is
10821 case-sensitive
10822
10823 */
10824 10426 void do_get_replace_regex(struct st_command *command) {
10825 10426 const char *expr = command->first_argument;
10826 10426 free_replace_regex();
10827 /* Allow variable for the *entire* list of replacements */
10828
2/2
✓ Branch 0 taken 945 times.
✓ Branch 1 taken 9481 times.
10426 if (*expr == '$') {
10829 945 VAR *val = var_get(expr, nullptr, false, true);
10830
1/2
✓ Branch 0 taken 945 times.
✗ Branch 1 not taken.
945 expr = val ? val->str_val : nullptr;
10831 }
10832
5/8
✓ Branch 0 taken 10426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10237 times.
✓ Branch 3 taken 189 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10216 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 10405 times.
10426 if (expr && *expr && !(glob_replace_regex = init_replace_regex(expr)))
10833 die("Could not init replace_regex");
10834 10405 command->last_argument = command->end;
10835 10405 }
10836
10837 6275802 void free_replace_regex() {
10838
2/2
✓ Branch 0 taken 10216 times.
✓ Branch 1 taken 6265586 times.
6275802 if (glob_replace_regex) {
10839 10216 my_free(glob_replace_regex->even_buf);
10840 10216 my_free(glob_replace_regex->odd_buf);
10841 10216 glob_replace_regex->~st_replace_regex();
10842 10216 my_free(glob_replace_regex);
10843 10216 glob_replace_regex = nullptr;
10844 }
10845 6275802 }
10846
10847 #ifndef WORD_BIT
10848 #define WORD_BIT (8 * sizeof(uint))
10849 #endif
10850
10851 #define SET_MALLOC_HUNC 64
10852 #define LAST_CHAR_CODE 259
10853
10854 struct REP_SET {
10855 uint *bits; /* Pointer to used sets */
10856 short next[LAST_CHAR_CODE]; /* Pointer to next sets */
10857 uint found_len; /* Best match to date */
10858 int found_offset;
10859 uint table_offset;
10860 uint size_of_bits; /* For convenience */
10861 };
10862
10863 struct REP_SETS {
10864 uint count; /* Number of sets */
10865 uint extra; /* Extra sets in buffer */
10866 uint invisible; /* Sets not chown */
10867 uint size_of_bits;
10868 REP_SET *set, *set_buffer;
10869 uint *bit_buffer;
10870 };
10871
10872 struct FOUND_SET {
10873 uint table_offset;
10874 int found_offset;
10875 };
10876
10877 struct FOLLOWS {
10878 int chr;
10879 uint table_offset;
10880 uint len;
10881 };
10882
10883 int init_sets(REP_SETS *sets, uint states);
10884 REP_SET *make_new_set(REP_SETS *sets);
10885 void make_sets_invisible(REP_SETS *sets);
10886 void free_last_set(REP_SETS *sets);
10887 void free_sets(REP_SETS *sets);
10888 void internal_set_bit(REP_SET *set, uint bit);
10889 void internal_clear_bit(REP_SET *set, uint bit);
10890 void or_bits(REP_SET *to, REP_SET *from);
10891 void copy_bits(REP_SET *to, REP_SET *from);
10892 int cmp_bits(REP_SET *set1, REP_SET *set2);
10893 int get_next_bit(REP_SET *set, uint lastpos);
10894 int find_set(REP_SETS *sets, REP_SET *find);
10895 int find_found(FOUND_SET *found_set, uint table_offset, int found_offset);
10896 uint start_at_word(const char *pos);
10897 uint end_of_word(const char *pos);
10898
10899 static uint found_sets = 0;
10900
10901 108621 static uint replace_len(const char *str) {
10902 108621 uint len = 0;
10903
2/2
✓ Branch 0 taken 2060836 times.
✓ Branch 1 taken 108621 times.
2169457 while (*str) {
10904 2060836 str++;
10905 2060836 len++;
10906 }
10907 108621 return len;
10908 }
10909
10910 /* Init a replace structure for further calls */
10911
10912 32534 REPLACE *init_replace(const char **from, const char **to, uint count,
10913 const char *word_end_chars) {
10914 static const int SPACE_CHAR = 256;
10915 static const int END_OF_LINE = 258;
10916
10917 uint i, j, states, set_nr, len, result_len, max_length, found_end, bits_set,
10918 bit_nr;
10919 int used_sets, chr, default_state;
10920 char used_chars[LAST_CHAR_CODE], is_word_end[256];
10921 const char *pos, **to_array;
10922 char *to_pos;
10923 REP_SETS sets;
10924 REP_SET *set, *start_states, *word_states, *new_set;
10925 FOLLOWS *follow, *follow_ptr;
10926 REPLACE *replace;
10927 FOUND_SET *found_set;
10928 REPLACE_STRING *rep_str;
10929
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 DBUG_TRACE;
10930
10931 /* Count number of states */
10932
2/2
✓ Branch 0 taken 52983 times.
✓ Branch 1 taken 32534 times.
85517 for (i = result_len = max_length = 0, states = 2; i < count; i++) {
10933 52983 len = replace_len(from[i]);
10934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 52983 times.
52983 if (!len) {
10935 errno = EINVAL;
10936 return nullptr;
10937 }
10938 52983 states += len + 1;
10939 52983 result_len += (uint)std::strlen(to[i]) + 1;
10940
2/2
✓ Branch 0 taken 49771 times.
✓ Branch 1 taken 3212 times.
52983 if (len > max_length) max_length = len;
10941 }
10942 32534 memset(is_word_end, 0, sizeof(is_word_end));
10943
2/2
✓ Branch 0 taken 195258 times.
✓ Branch 1 taken 32534 times.
227792 for (i = 0; word_end_chars[i]; i++) is_word_end[(uchar)word_end_chars[i]] = 1;
10944
10945
2/4
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 32534 times.
32534 if (init_sets(&sets, states)) return nullptr;
10946 32534 found_sets = 0;
10947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32534 times.
32534 if (!(found_set = (FOUND_SET *)my_malloc(
10948
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 PSI_NOT_INSTRUMENTED, sizeof(FOUND_SET) * max_length * count,
10949 MYF(MY_WME)))) {
10950 free_sets(&sets);
10951 return nullptr;
10952 }
10953
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 (void)make_new_set(&sets); /* Set starting set */
10954 32534 make_sets_invisible(&sets); /* Hide previous sets */
10955 32534 used_sets = -1;
10956
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 word_states = make_new_set(&sets); /* Start of new word */
10957
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 start_states = make_new_set(&sets); /* This is first state */
10958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32534 times.
32534 if (!(follow = (FOLLOWS *)my_malloc(PSI_NOT_INSTRUMENTED,
10959
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 (states + 2) * sizeof(FOLLOWS),
10960 MYF(MY_WME)))) {
10961 free_sets(&sets);
10962 my_free(found_set);
10963 return nullptr;
10964 }
10965
10966 /* Init follow_ptr[] */
10967
2/2
✓ Branch 0 taken 52983 times.
✓ Branch 1 taken 32534 times.
85517 for (i = 0, states = 1, follow_ptr = follow + 1; i < count; i++) {
10968
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 52862 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
52983 if (from[i][0] == '\\' && from[i][1] == '^') {
10969 internal_set_bit(start_states, states + 1);
10970 if (!from[i][2]) {
10971 start_states->table_offset = i;
10972 start_states->found_offset = 1;
10973 }
10974
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 52862 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
52983 } else if (from[i][0] == '\\' && from[i][1] == '$') {
10975 internal_set_bit(start_states, states);
10976 internal_set_bit(word_states, states);
10977 if (!from[i][2] && start_states->table_offset == (uint)~0) {
10978 start_states->table_offset = i;
10979 start_states->found_offset = 0;
10980 }
10981 } else {
10982 52983 internal_set_bit(word_states, states);
10983
3/6
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 52862 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
52983 if (from[i][0] == '\\' && (from[i][1] == 'b' && from[i][2]))
10984 internal_set_bit(start_states, states + 1);
10985 else
10986 52983 internal_set_bit(start_states, states);
10987 }
10988
2/2
✓ Branch 0 taken 980916 times.
✓ Branch 1 taken 52983 times.
1033899 for (pos = from[i], len = 0; *pos; pos++) {
10989 980916 follow_ptr->chr = (uchar)*pos;
10990 980916 follow_ptr->table_offset = i;
10991 980916 follow_ptr->len = ++len;
10992 980916 follow_ptr++;
10993 }
10994 52983 follow_ptr->chr = 0;
10995 52983 follow_ptr->table_offset = i;
10996 52983 follow_ptr->len = len;
10997 52983 follow_ptr++;
10998 52983 states += (uint)len + 1;
10999 }
11000
11001
2/2
✓ Branch 0 taken 959268 times.
✓ Branch 1 taken 32534 times.
991802 for (set_nr = 0, pos = nullptr; set_nr < sets.count; set_nr++) {
11002 959268 set = sets.set + set_nr;
11003 959268 default_state = 0; /* Start from beginning */
11004
11005 /* If end of found-string not found or start-set with current set */
11006
11007
2/2
✓ Branch 0 taken 22681271 times.
✓ Branch 1 taken 959268 times.
23640539 for (i = (uint)~0; (i = get_next_bit(set, i));) {
11008
2/2
✓ Branch 0 taken 3001 times.
✓ Branch 1 taken 22678270 times.
22681271 if (!follow[i].chr) {
11009
1/2
✓ Branch 0 taken 3001 times.
✗ Branch 1 not taken.
3001 if (!default_state)
11010 default_state =
11011 3001 find_found(found_set, set->table_offset, set->found_offset + 1);
11012 }
11013 }
11014 959268 copy_bits(sets.set + used_sets, set); /* Save set for changes */
11015
2/2
✓ Branch 0 taken 956267 times.
✓ Branch 1 taken 3001 times.
959268 if (!default_state)
11016 956267 or_bits(sets.set + used_sets, sets.set); /* Can restart from start */
11017
11018 /* Find all chars that follows current sets */
11019 959268 memset(used_chars, 0, sizeof(used_chars));
11020
2/2
✓ Branch 0 taken 24208041 times.
✓ Branch 1 taken 959268 times.
25167309 for (i = (uint)~0; (i = get_next_bit(sets.set + used_sets, i));) {
11021 24208041 used_chars[follow[i].chr] = 1;
11022
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24208041 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24208041 if ((follow[i].chr == SPACE_CHAR && !follow[i + 1].chr &&
11023 follow[i].len > 1) ||
11024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24208041 times.
24208041 follow[i].chr == END_OF_LINE)
11025 used_chars[0] = 1;
11026 }
11027
11028 /* Mark word_chars used if \b is in state */
11029
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 959268 times.
959268 if (used_chars[SPACE_CHAR])
11030 for (pos = word_end_chars; *pos; pos++) used_chars[(int)(uchar)*pos] = 1;
11031
11032 /* Handle other used characters */
11033
2/2
✓ Branch 0 taken 245572608 times.
✓ Branch 1 taken 959268 times.
246531876 for (chr = 0; chr < 256; chr++) {
11034
2/2
✓ Branch 0 taken 243176682 times.
✓ Branch 1 taken 2395926 times.
245572608 if (!used_chars[chr])
11035
2/2
✓ Branch 0 taken 242220415 times.
✓ Branch 1 taken 956267 times.
243176682 set->next[chr] = chr ? default_state : -1;
11036 else {
11037
1/2
✓ Branch 0 taken 2395926 times.
✗ Branch 1 not taken.
2395926 new_set = make_new_set(&sets);
11038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2395926 times.
2395926 assert(new_set);
11039 2395926 set = sets.set + set_nr; /* if realloc */
11040 2395926 new_set->table_offset = set->table_offset;
11041 2395926 new_set->found_len = set->found_len;
11042 2395926 new_set->found_offset = set->found_offset + 1;
11043 2395926 found_end = 0;
11044
11045
2/2
✓ Branch 0 taken 30306657 times.
✓ Branch 1 taken 2395926 times.
32702583 for (i = (uint)~0; (i = get_next_bit(sets.set + used_sets, i));) {
11046
4/4
✓ Branch 0 taken 30300628 times.
✓ Branch 1 taken 6029 times.
✓ Branch 2 taken 6095588 times.
✓ Branch 3 taken 24205040 times.
30306657 if (!follow[i].chr || follow[i].chr == chr ||
11047
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6095588 times.
6095588 (follow[i].chr == SPACE_CHAR &&
11048 (is_word_end[chr] ||
11049 (!chr && follow[i].len > 1 && !follow[i + 1].chr))) ||
11050
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6095588 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6095588 (follow[i].chr == END_OF_LINE && !chr)) {
11051
6/6
✓ Branch 0 taken 24208068 times.
✓ Branch 1 taken 3001 times.
✓ Branch 2 taken 24205040 times.
✓ Branch 3 taken 3028 times.
✓ Branch 4 taken 87190 times.
✓ Branch 5 taken 24117850 times.
24211069 if ((!chr || (follow[i].chr && !follow[i + 1].chr)) &&
11052
2/2
✓ Branch 0 taken 90187 times.
✓ Branch 1 taken 4 times.
90191 follow[i].len > found_end)
11053 90187 found_end = follow[i].len;
11054
4/4
✓ Branch 0 taken 24208068 times.
✓ Branch 1 taken 3001 times.
✓ Branch 2 taken 24205040 times.
✓ Branch 3 taken 3028 times.
24211069 if (chr && follow[i].chr)
11055 24205040 internal_set_bit(new_set, i + 1); /* To next set */
11056 else
11057 6029 internal_set_bit(new_set, i);
11058 }
11059 }
11060
2/2
✓ Branch 0 taken 90091 times.
✓ Branch 1 taken 2305835 times.
2395926 if (found_end) {
11061 90091 new_set->found_len = 0; /* Set for testing if first */
11062 90091 bits_set = 0;
11063
2/2
✓ Branch 0 taken 114736 times.
✓ Branch 1 taken 90091 times.
204827 for (i = (uint)~0; (i = get_next_bit(new_set, i));) {
11064
2/6
✓ Branch 0 taken 114736 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 114736 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
114736 if ((follow[i].chr == SPACE_CHAR || follow[i].chr == END_OF_LINE) &&
11065 !chr)
11066 bit_nr = i + 1;
11067 else
11068 114736 bit_nr = i;
11069
2/2
✓ Branch 0 taken 90332 times.
✓ Branch 1 taken 24404 times.
114736 if (follow[bit_nr - 1].len < found_end ||
11070
5/6
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 90132 times.
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 196 times.
90332 (new_set->found_len && (chr == 0 || !follow[bit_nr].chr)))
11071 24408 internal_clear_bit(new_set, i);
11072 else {
11073
4/4
✓ Branch 0 taken 87327 times.
✓ Branch 1 taken 3001 times.
✓ Branch 2 taken 87090 times.
✓ Branch 3 taken 237 times.
90328 if (chr == 0 || !follow[bit_nr].chr) { /* best match */
11074 90091 new_set->table_offset = follow[bit_nr].table_offset;
11075
3/4
✓ Branch 0 taken 3001 times.
✓ Branch 1 taken 87090 times.
✓ Branch 2 taken 3001 times.
✗ Branch 3 not taken.
90091 if (chr || (follow[i].chr == SPACE_CHAR ||
11076
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3001 times.
3001 follow[i].chr == END_OF_LINE))
11077 87090 new_set->found_offset = found_end; /* New match */
11078 90091 new_set->found_len = found_end;
11079 }
11080 90328 bits_set++;
11081 }
11082 }
11083
2/2
✓ Branch 0 taken 89893 times.
✓ Branch 1 taken 198 times.
90091 if (bits_set == 1) {
11084 89893 set->next[chr] = find_found(found_set, new_set->table_offset,
11085 new_set->found_offset);
11086 89893 free_last_set(&sets);
11087 } else
11088 198 set->next[chr] = find_set(&sets, new_set);
11089 } else
11090 2305835 set->next[chr] = find_set(&sets, new_set);
11091 }
11092 }
11093 }
11094
11095 /* Alloc replace structure for the replace-state-machine */
11096
11097 32534 if ((replace =
11098
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 (REPLACE *)my_malloc(PSI_NOT_INSTRUMENTED,
11099 32534 sizeof(REPLACE) * (sets.count) +
11100 32534 sizeof(REPLACE_STRING) * (found_sets + 1) +
11101
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 sizeof(char *) * count + result_len,
11102 MYF(MY_WME | MY_ZEROFILL)))) {
11103 32534 rep_str = (REPLACE_STRING *)(replace + sets.count);
11104 32534 to_array = pointer_cast<const char **>(rep_str + found_sets + 1);
11105 32534 to_pos = (char *)(to_array + count);
11106
2/2
✓ Branch 0 taken 52983 times.
✓ Branch 1 taken 32534 times.
85517 for (i = 0; i < count; i++) {
11107 52983 to_array[i] = to_pos;
11108 52983 to_pos = my_stpcpy(to_pos, to[i]) + 1;
11109 }
11110 32534 rep_str[0].found = 1;
11111 32534 rep_str[0].replace_string = nullptr;
11112
2/2
✓ Branch 0 taken 55638 times.
✓ Branch 1 taken 32534 times.
88172 for (i = 1; i <= found_sets; i++) {
11113 55638 pos = from[found_set[i - 1].table_offset];
11114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55638 times.
55638 rep_str[i].found = !memcmp(pos, "\\^", 3) ? 2 : 1;
11115 55638 rep_str[i].replace_string = to_array[found_set[i - 1].table_offset];
11116 55638 rep_str[i].to_offset = found_set[i - 1].found_offset - start_at_word(pos);
11117 55638 rep_str[i].from_offset =
11118 55638 found_set[i - 1].found_offset - replace_len(pos) + end_of_word(pos);
11119 }
11120
2/2
✓ Branch 0 taken 959268 times.
✓ Branch 1 taken 32534 times.
991802 for (i = 0; i < sets.count; i++) {
11121
2/2
✓ Branch 0 taken 245572608 times.
✓ Branch 1 taken 959268 times.
246531876 for (j = 0; j < 256; j++)
11122
2/2
✓ Branch 0 taken 243764221 times.
✓ Branch 1 taken 1808387 times.
245572608 if (sets.set[i].next[j] >= 0)
11123 243764221 replace[i].next[j] = replace + sets.set[i].next[j];
11124 else
11125 1808387 replace[i].next[j] =
11126 1808387 (REPLACE *)(rep_str + (-sets.set[i].next[j] - 1));
11127 }
11128 }
11129
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 my_free(follow);
11130
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 free_sets(&sets);
11131
1/2
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
32534 my_free(found_set);
11132
3/8
✓ Branch 0 taken 32534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32534 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32534 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
32534 DBUG_PRINT("exit", ("Replace table has %d states", sets.count));
11133 32534 return replace;
11134 32534 }
11135
11136 32534 int init_sets(REP_SETS *sets, uint states) {
11137 32534 memset(sets, 0, sizeof(*sets));
11138 32534 sets->size_of_bits = ((states + 7) / 8);
11139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32534 times.
32534 if (!(sets->set_buffer = (REP_SET *)my_malloc(
11140 PSI_NOT_INSTRUMENTED, sizeof(REP_SET) * SET_MALLOC_HUNC,
11141 MYF(MY_WME))))
11142 return 1;
11143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32534 times.
32534 if (!(sets->bit_buffer = (uint *)my_malloc(
11144 PSI_NOT_INSTRUMENTED,
11145 32534 sizeof(uint) * sets->size_of_bits * SET_MALLOC_HUNC,
11146 MYF(MY_WME)))) {
11147 my_free(sets->set);
11148 return 1;
11149 }
11150 32534 return 0;
11151 }
11152
11153 /* Make help sets invisible for nicer coding */
11154
11155 32534 void make_sets_invisible(REP_SETS *sets) {
11156 32534 sets->invisible = sets->count;
11157 32534 sets->set += sets->count;
11158 32534 sets->count = 0;
11159 32534 }
11160
11161 2528808 REP_SET *make_new_set(REP_SETS *sets) {
11162 uint i, count, *bit_buffer;
11163 REP_SET *set;
11164
2/2
✓ Branch 0 taken 2493528 times.
✓ Branch 1 taken 35280 times.
2528808 if (sets->extra) {
11165 2493528 sets->extra--;
11166 2493528 set = sets->set + sets->count++;
11167 2493528 memset(set->bits, 0, sizeof(uint) * sets->size_of_bits);
11168 2493528 memset(&set->next[0], 0, sizeof(set->next[0]) * LAST_CHAR_CODE);
11169 2493528 set->found_offset = 0;
11170 2493528 set->found_len = 0;
11171 2493528 set->table_offset = (uint)~0;
11172 2493528 set->size_of_bits = sets->size_of_bits;
11173 2493528 return set;
11174 }
11175 35280 count = sets->count + sets->invisible + SET_MALLOC_HUNC;
11176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35280 times.
35280 if (!(set = (REP_SET *)my_realloc(PSI_NOT_INSTRUMENTED,
11177 35280 (uchar *)sets->set_buffer,
11178 35280 sizeof(REP_SET) * count, MYF(MY_WME))))
11179 return nullptr;
11180 35280 sets->set_buffer = set;
11181 35280 sets->set = set + sets->invisible;
11182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35280 times.
35280 if (!(bit_buffer = (uint *)my_realloc(
11183 35280 PSI_NOT_INSTRUMENTED, (uchar *)sets->bit_buffer,
11184 35280 (sizeof(uint) * sets->size_of_bits) * count, MYF(MY_WME))))
11185 return nullptr;
11186 35280 sets->bit_buffer = bit_buffer;
11187
2/2
✓ Branch 0 taken 2851648 times.
✓ Branch 1 taken 35280 times.
2886928 for (i = 0; i < count; i++) {
11188 2851648 sets->set_buffer[i].bits = bit_buffer;
11189 2851648 bit_buffer += sets->size_of_bits;
11190 }
11191 35280 sets->extra = SET_MALLOC_HUNC;
11192 35280 return make_new_set(sets);
11193 }
11194
11195 1501726 void free_last_set(REP_SETS *sets) {
11196 1501726 sets->count--;
11197 1501726 sets->extra++;
11198 1501726 return;
11199 }
11200
11201 32534 void free_sets(REP_SETS *sets) {
11202 32534 my_free(sets->set_buffer);
11203 32534 my_free(sets->bit_buffer);
11204 32534 return;
11205 }
11206
11207 24317035 void internal_set_bit(REP_SET *set, uint bit) {
11208 24317035 set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT);
11209 24317035 return;
11210 }
11211
11212 24408 void internal_clear_bit(REP_SET *set, uint bit) {
11213 24408 set->bits[bit / WORD_BIT] &= ~(1 << (bit % WORD_BIT));
11214 24408 return;
11215 }
11216
11217 956267 void or_bits(REP_SET *to, REP_SET *from) {
11218 uint i;
11219
2/2
✓ Branch 0 taken 13153198 times.
✓ Branch 1 taken 956267 times.
14109465 for (i = 0; i < to->size_of_bits; i++) to->bits[i] |= from->bits[i];
11220 956267 return;
11221 }
11222
11223 959268 void copy_bits(REP_SET *to, REP_SET *from) {
11224 959268 memcpy((uchar *)to->bits, (uchar *)from->bits,
11225 959268 (size_t)(sizeof(uint) * to->size_of_bits));
11226 959268 }
11227
11228 52087977 int cmp_bits(REP_SET *set1, REP_SET *set2) {
11229 52087977 return memcmp(set1->bits, set2->bits, sizeof(uint) * set1->size_of_bits);
11230 }
11231
11232 /* Get next set bit from set. */
11233
11234 81715258 int get_next_bit(REP_SET *set, uint lastpos) {
11235 uint pos, *start, *end, bits;
11236
11237 81715258 start = set->bits + ((lastpos + 1) / WORD_BIT);
11238 81715258 end = set->bits + set->size_of_bits;
11239 81715258 bits = start[0] & ~((1 << ((lastpos + 1) % WORD_BIT)) - 1U);
11240
11241
6/6
✓ Branch 0 taken 51016186 times.
✓ Branch 1 taken 77310705 times.
✓ Branch 2 taken 46611633 times.
✓ Branch 3 taken 4404553 times.
✓ Branch 4 taken 46611633 times.
✓ Branch 5 taken 81715258 times.
128326891 while (!bits && ++start < end) bits = start[0];
11242
2/2
✓ Branch 0 taken 4404553 times.
✓ Branch 1 taken 77310705 times.
81715258 if (!bits) return 0;
11243 77310705 pos = (uint)(start - set->bits) * WORD_BIT;
11244
2/2
✓ Branch 0 taken 1120034798 times.
✓ Branch 1 taken 77310705 times.
1197345503 while (!(bits & 1)) {
11245 1120034798 bits >>= 1;
11246 1120034798 pos++;
11247 }
11248 77310705 return pos;
11249 }
11250
11251 /* find if there is a same set in sets. If there is, use it and
11252 free given set, else put in given set in sets and return its
11253 position */
11254
11255 2306033 int find_set(REP_SETS *sets, REP_SET *find) {
11256 uint i;
11257
2/2
✓ Branch 0 taken 52087977 times.
✓ Branch 1 taken 894200 times.
52982177 for (i = 0; i < sets->count - 1; i++) {
11258
2/2
✓ Branch 0 taken 1411833 times.
✓ Branch 1 taken 50676144 times.
52087977 if (!cmp_bits(sets->set + i, find)) {
11259 1411833 free_last_set(sets);
11260 1411833 return i;
11261 }
11262 }
11263 894200 return i; /* return new position */
11264 }
11265
11266 /* find if there is a found_set with same table_offset & found_offset
11267 If there is return offset to it, else add new offset and return pos.
11268 Pos returned is -offset-2 in found_set_structure because it is
11269 saved in set->next and set->next[] >= 0 points to next set and
11270 set->next[] == -1 is reserved for end without replaces.
11271 */
11272
11273 92894 int find_found(FOUND_SET *found_set, uint table_offset, int found_offset) {
11274 int i;
11275
2/2
✓ Branch 0 taken 123411 times.
✓ Branch 1 taken 55638 times.
179049 for (i = 0; (uint)i < found_sets; i++)
11276
2/2
✓ Branch 0 taken 89476 times.
✓ Branch 1 taken 33935 times.
123411 if (found_set[i].table_offset == table_offset &&
11277
2/2
✓ Branch 0 taken 37256 times.
✓ Branch 1 taken 52220 times.
89476 found_set[i].found_offset == found_offset)
11278 37256 return -i - 2;
11279 55638 found_set[i].table_offset = table_offset;
11280 55638 found_set[i].found_offset = found_offset;
11281 55638 found_sets++;
11282 55638 return -i - 2; /* return new position */
11283 }
11284
11285 /* Return 1 if regexp starts with \b or ends with \b*/
11286
11287 55638 uint start_at_word(const char *pos) {
11288
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 55638 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 55638 times.
55638 return (((!memcmp(pos, "\\b", 2) && pos[2]) || !memcmp(pos, "\\^", 2)) ? 1
11289 55638 : 0);
11290 }
11291
11292 55638 uint end_of_word(const char *pos) {
11293 55638 const char *end = strend(pos);
11294
1/2
✓ Branch 0 taken 54047 times.
✗ Branch 1 not taken.
54047 return ((end > pos + 2 && !memcmp(end - 2, "\\b", 2)) ||
11295
3/4
✓ Branch 0 taken 54667 times.
✓ Branch 1 taken 971 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54667 times.
55638 (end >= pos + 2 && !memcmp(end - 2, "\\$", 2)))
11296
2/2
✓ Branch 0 taken 54047 times.
✓ Branch 1 taken 1591 times.
111276 ? 1
11297 55638 : 0;
11298 }
11299
11300 /****************************************************************************
11301 * Handle replacement of strings
11302 ****************************************************************************/
11303
11304 #define PC_MALLOC 256 /* Bytes for pointers */
11305 #define PS_MALLOC 512 /* Bytes for data */
11306
11307 105978 int insert_pointer_name(POINTER_ARRAY *pa, char *name) {
11308 uint i, length, old_count;
11309 uchar *new_pos;
11310 const char **new_array;
11311
1/2
✓ Branch 0 taken 105978 times.
✗ Branch 1 not taken.
105978 DBUG_TRACE;
11312
11313
2/2
✓ Branch 0 taken 65080 times.
✓ Branch 1 taken 40898 times.
105978 if (!pa->typelib.count) {
11314 65080 if (!(pa->typelib.type_names =
11315
2/4
✓ Branch 0 taken 65080 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 65080 times.
65080 (const char **)my_malloc(PSI_NOT_INSTRUMENTED,
11316 ((PC_MALLOC - MALLOC_OVERHEAD) /
11317 (sizeof(char *) + sizeof(*pa->flag)) *
11318 (sizeof(char *) + sizeof(*pa->flag))),
11319 MYF(MY_WME))))
11320 return -1;
11321
2/4
✓ Branch 0 taken 65080 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 65080 times.
65080 if (!(pa->str = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED,
11322 (uint)(PS_MALLOC - MALLOC_OVERHEAD),
11323 MYF(MY_WME)))) {
11324 my_free(pa->typelib.type_names);
11325 return -1;
11326 }
11327 65080 pa->max_count =
11328 (PC_MALLOC - MALLOC_OVERHEAD) / (sizeof(uchar *) + sizeof(*pa->flag));
11329 65080 pa->flag = (uint8 *)(pa->typelib.type_names + pa->max_count);
11330 65080 pa->length = 0;
11331 65080 pa->max_length = PS_MALLOC - MALLOC_OVERHEAD;
11332 65080 pa->array_allocs = 1;
11333 }
11334 105978 length = (uint)std::strlen(name) + 1;
11335
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 105949 times.
105978 if (pa->length + length >= pa->max_length) {
11336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 if (!(new_pos = (uchar *)my_realloc(PSI_NOT_INSTRUMENTED, (uchar *)pa->str,
11337
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 (uint)(pa->length + length + PS_MALLOC),
11338 MYF(MY_WME))))
11339 return 1;
11340
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if (new_pos != pa->str) {
11341 29 ptrdiff_t diff = new_pos - pa->str;
11342
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 29 times.
65 for (i = 0; i < pa->typelib.count; i++)
11343 36 pa->typelib.type_names[i] = pa->typelib.type_names[i] + diff;
11344 29 pa->str = new_pos;
11345 }
11346 29 pa->max_length = pa->length + length + PS_MALLOC;
11347 }
11348
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 105976 times.
105978 if (pa->typelib.count >= pa->max_count - 1) {
11349 int len;
11350 2 pa->array_allocs++;
11351 2 len = (PC_MALLOC * pa->array_allocs - MALLOC_OVERHEAD);
11352
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!(new_array = (const char **)my_realloc(
11353 2 PSI_NOT_INSTRUMENTED, (uchar *)pa->typelib.type_names,
11354
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (uint)len / (sizeof(uchar *) + sizeof(*pa->flag)) *
11355 (sizeof(uchar *) + sizeof(*pa->flag)),
11356 MYF(MY_WME))))
11357 return 1;
11358 2 pa->typelib.type_names = new_array;
11359 2 old_count = pa->max_count;
11360 2 pa->max_count = len / (sizeof(uchar *) + sizeof(*pa->flag));
11361 2 pa->flag = (uint8 *)(pa->typelib.type_names + pa->max_count);
11362 2 memcpy((uchar *)pa->flag, (char *)(pa->typelib.type_names + old_count),
11363 old_count * sizeof(*pa->flag));
11364 }
11365 105978 pa->flag[pa->typelib.count] = 0; /* Reset flag */
11366 105978 pa->typelib.type_names[pa->typelib.count++] = (char *)pa->str + pa->length;
11367 105978 pa->typelib.type_names[pa->typelib.count] = NullS; /* Put end-mark */
11368 105978 (void)my_stpcpy((char *)pa->str + pa->length, name);
11369 105978 pa->length += length;
11370 105978 return 0;
11371 105978 } /* insert_pointer_name */
11372
11373 /* free pointer array */
11374
11375 65068 void free_pointer_array(POINTER_ARRAY *pa) {
11376
1/2
✓ Branch 0 taken 65068 times.
✗ Branch 1 not taken.
65068 if (pa->typelib.count) {
11377 65068 pa->typelib.count = 0;
11378 65068 my_free(pa->typelib.type_names);
11379 65068 pa->typelib.type_names = nullptr;
11380 65068 my_free(pa->str);
11381 }
11382 65068 } /* free_pointer_array */
11383
11384 /* Functions that uses replace and replace_regex */
11385
11386 /* Append the string to ds, with optional replace */
11387 252497321 void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
11388 size_t len) {
11389 #ifdef _WIN32
11390 fix_win_paths(val, len);
11391 #endif
11392
11393
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 252497228 times.
252497321 if (display_result_lower) {
11394 /* Convert to lower case, and do this first */
11395
1/2
✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
93 my_casedn_str(charset_info, const_cast<char *>(val));
11396 }
11397
11398
2/2
✓ Branch 0 taken 148226 times.
✓ Branch 1 taken 252349095 times.
252497321 if (glob_replace_regex) {
11399 148226 size_t orig_len = len;
11400 // Regex replace
11401
3/4
✓ Branch 0 taken 148202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33736 times.
✓ Branch 3 taken 114466 times.
148226 if (!multi_reg_replace(glob_replace_regex, const_cast<char *>(val), &len)) {
11402 33736 val = glob_replace_regex->buf;
11403 } else {
11404 114466 len = orig_len;
11405 }
11406 }
11407
11408 DYNAMIC_STRING ds_temp;
11409
1/2
✓ Branch 0 taken 252497297 times.
✗ Branch 1 not taken.
252497297 init_dynamic_string(&ds_temp, "", 512);
11410
11411 /* Store result from replace_result in ds_temp */
11412
2/2
✓ Branch 0 taken 270225 times.
✓ Branch 1 taken 252227072 times.
252497297 if (glob_replace) {
11413 /* Normal replace */
11414
1/2
✓ Branch 0 taken 270225 times.
✗ Branch 1 not taken.
270225 replace_strings_append(glob_replace, &ds_temp, val, len);
11415 }
11416
11417 /*
11418 Call the replace_numeric_round function with the specified
11419 precision. It may be used along with replace_result, so use the
11420 output from replace_result as the input for replace_numeric_round.
11421 */
11422
2/2
✓ Branch 0 taken 3704 times.
✓ Branch 1 taken 252493593 times.
252497297 if (glob_replace_numeric_round >= 0) {
11423 /* Copy the result from replace_result if it was used, into buffer */
11424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3704 times.
3704 if (ds_temp.length > 0) {
11425 char buffer[512];
11426 strcpy(buffer, ds_temp.str);
11427 dynstr_free(&ds_temp);
11428 init_dynamic_string(&ds_temp, "", 512);
11429 replace_numeric_round_append(glob_replace_numeric_round, &ds_temp, buffer,
11430 std::strlen(buffer));
11431 } else
11432
1/2
✓ Branch 0 taken 3704 times.
✗ Branch 1 not taken.
3704 replace_numeric_round_append(glob_replace_numeric_round, &ds_temp, val,
11433 len);
11434 }
11435
11436
4/4
✓ Branch 0 taken 252227072 times.
✓ Branch 1 taken 270225 times.
✓ Branch 2 taken 252223368 times.
✓ Branch 3 taken 3704 times.
252497297 if (!glob_replace && glob_replace_numeric_round < 0)
11437
1/2
✓ Branch 0 taken 252223368 times.
✗ Branch 1 not taken.
252223368 dynstr_append_mem(ds, val, len);
11438 else
11439
1/2
✓ Branch 0 taken 273929 times.
✗ Branch 1 not taken.
273929 dynstr_append_mem(ds, ds_temp.str, std::strlen(ds_temp.str));
11440
1/2
✓ Branch 0 taken 252497297 times.
✗ Branch 1 not taken.
252497297 dynstr_free(&ds_temp);
11441 252497297 }
11442
11443 /* Append zero-terminated string to ds, with optional replace */
11444 14839568 void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val) {
11445 14839568 replace_dynstr_append_mem(ds, val, std::strlen(val));
11446 14839568 }
11447
11448 /* Append uint to ds, with optional replace */
11449 21165 void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val) {
11450 char buff[22]; /* This should be enough for any int */
11451
1/2
✓ Branch 0 taken 21165 times.
✗ Branch 1 not taken.
21165 char *end = longlong10_to_str(val, buff, 10);
11452
1/2
✓ Branch 0 taken 21165 times.
✗ Branch 1 not taken.
21165 replace_dynstr_append_mem(ds, buff, end - buff);
11453 21165 }
11454
11455 /*
11456 Build a list of pointer to each line in ds_input, sort
11457 the list and use the sorted list to append the strings
11458 sorted to the output ds
11459
11460 SYNOPSIS
11461 dynstr_append_sorted
11462 ds - string where the sorted output will be appended
11463 ds_input - string to be sorted
11464 start_sort_column - column to start sorting from (0 for sorting
11465 the entire line); a stable sort will be used
11466 */
11467
11468 class Comp_lines {
11469 public:
11470 bool operator()(const char *a, const char *b) {
11471 return std::strcmp(a, b) < 0;
11472 }
11473 };
11474
11475 532 static size_t length_of_n_first_columns(std::string str,
11476 int start_sort_column) {
11477
1/2
✓ Branch 0 taken 532 times.
✗ Branch 1 not taken.
532 std::stringstream columns(str);
11478 532 std::string temp;
11479 532 size_t size_of_columns = 0;
11480
11481 532 int i = 0;
11482
8/10
✓ Branch 0 taken 1237 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1237 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1228 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 705 times.
✓ Branch 7 taken 523 times.
✓ Branch 8 taken 705 times.
✓ Branch 9 taken 532 times.
1237 while (getline(columns, temp, '\t') && i < start_sort_column) {
11483 705 size_of_columns = size_of_columns + temp.length();
11484 705 i++;
11485 }
11486
11487 532 return size_of_columns;
11488 532 }
11489
11490 28584 void dynstr_append_sorted(DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_input,
11491 int start_sort_column) {
11492 28584 char *start = ds_input->str;
11493 28584 char *end = ds_input->str + ds_input->length;
11494 28584 std::vector<std::string> sorted;
11495
1/2
✓ Branch 0 taken 28584 times.
✗ Branch 1 not taken.
28584 DBUG_TRACE;
11496
11497
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 28347 times.
28584 if (!*start) return; /* No input */
11498
11499 /* First line is result header, skip past it */
11500
3/4
✓ Branch 0 taken 315801 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 287454 times.
✓ Branch 3 taken 28347 times.
315801 while (*start && *start != '\n') start++;
11501 28347 start++; /* Skip past \n */
11502
1/2
✓ Branch 0 taken 28347 times.
✗ Branch 1 not taken.
28347 dynstr_append_mem(ds, ds_input->str, start - ds_input->str);
11503
11504 /*
11505 Traverse through the result set from start to end to avoid
11506 ignoring null characters (0x00), and insert line by line
11507 into array.
11508 */
11509 28347 size_t first_unsorted_row = 0;
11510
2/2
✓ Branch 0 taken 224282 times.
✓ Branch 1 taken 28347 times.
252629 while (start < end) {
11511 224282 char *line_end = (char *)start;
11512
11513 /* Find end of line */
11514
2/2
✓ Branch 0 taken 5578725 times.
✓ Branch 1 taken 224282 times.
5803007 while (*line_end != '\n') line_end++;
11515 224282 *line_end = 0;
11516
11517
1/2
✓ Branch 0 taken 224282 times.
✗ Branch 1 not taken.
224282 std::string result_row = std::string(start, line_end - start);
11518
6/6
✓ Branch 0 taken 204439 times.
✓ Branch 1 taken 19843 times.
✓ Branch 2 taken 532 times.
✓ Branch 3 taken 203907 times.
✓ Branch 4 taken 532 times.
✓ Branch 5 taken 223750 times.
224282 if (!sorted.empty() && start_sort_column > 0) {
11519 /*
11520 If doing partial sorting, and the prefix is different from that of the
11521 previous line, the group is done. Sort it and start another one.
11522 */
11523 size_t prev_line_prefix_len =
11524
2/4
✓ Branch 0 taken 532 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 532 times.
✗ Branch 3 not taken.
532 length_of_n_first_columns(sorted.back(), start_sort_column);
11525
1/2
✓ Branch 0 taken 532 times.
✗ Branch 1 not taken.
532 if (sorted.back().compare(0, prev_line_prefix_len, result_row, 0,
11526
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 337 times.
532 prev_line_prefix_len) != 0) {
11527
1/2
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
195 std::sort(sorted.begin() + first_unsorted_row, sorted.end());
11528 195 first_unsorted_row = sorted.size();
11529 }
11530 }
11531
11532 /* Insert line into the array */
11533
1/2
✓ Branch 0 taken 224282 times.
✗ Branch 1 not taken.
224282 sorted.push_back(result_row);
11534 224282 start = line_end + 1;
11535 224282 }
11536
11537 /* Sort array */
11538
1/2
✓ Branch 0 taken 28347 times.
✗ Branch 1 not taken.
28347 std::stable_sort(sorted.begin() + first_unsorted_row, sorted.end());
11539
11540 /* Create new result */
11541
3/4
✓ Branch 0 taken 224282 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 224282 times.
✓ Branch 3 taken 28347 times.
252629 for (auto i : sorted) {
11542
1/2
✓ Branch 0 taken 224282 times.
✗ Branch 1 not taken.
224282 dynstr_append_mem(ds, i.c_str(), i.length());
11543
1/2
✓ Branch 0 taken 224282 times.
✗ Branch 1 not taken.
224282 dynstr_append(ds, "\n");
11544 224282 }
11545
4/4
✓ Branch 0 taken 28347 times.
✓ Branch 1 taken 237 times.
✓ Branch 2 taken 28347 times.
✓ Branch 3 taken 237 times.
28821 }
11546